diff options
199 files changed, 104806 insertions, 0 deletions
diff --git a/lib/libatm/Makefile b/lib/libatm/Makefile new file mode 100644 index 0000000..d861b81 --- /dev/null +++ b/lib/libatm/Makefile @@ -0,0 +1,37 @@ +# +# +# =================================== +# 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. +# +# @(#) $Id: Makefile,v 1.5 1998/07/10 16:01:58 jpt Exp $ +# +# + +LIB= atm +SRCS= atm_addr.c cache_key.c ioctl_subr.c ip_addr.c ip_checksum.c timer.c + +beforeinstall: + ${INSTALL} -C -o ${BINOWN} -g ${BINGRP} -m 444 ${.CURDIR}/libatm.h \ + ${DESTDIR}/usr/include + +.include <bsd.lib.mk> diff --git a/lib/libatm/atm_addr.c b/lib/libatm/atm_addr.c new file mode 100644 index 0000000..032107c --- /dev/null +++ b/lib/libatm/atm_addr.c @@ -0,0 +1,327 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_addr.c,v 1.1 1998/07/09 21:45:18 johnc Exp $ + * + */ + +/* + * User Space Library Functions + * ---------------------------- + * + * ATM address utility functions + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_addr.c,v 1.1 1998/07/09 21:45:18 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> +#include <string.h> + +#include <sys/socket.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_ioctl.h> + +#include "libatm.h" + + +extern char *prog; + + +/* + * Get NSAP, NSAP prefix or MAC address + * + * Arguments: + * in pointer to an address in ASCII + * out pointer to a buffer for the converted address + * len the length of the output buffer + * + * Returns: + * 0 error in format + * len the length of the data in the output buffer + * + */ +int +get_hex_atm_addr(in, out, len) + char *in; + u_char *out; + int len; +{ + int c_type, c_value, i, out_len, state, val; + + /* + * Character table + */ + static struct { + char c; + int type; + int value; + } char_table[] = { + {'.', 0, 0}, /* Type 0 -- period */ + {':', 0, 0}, /* Type 0 -- colon */ + {'0', 1, 0}, /* Type 1 -- hex digit */ + {'1', 1, 1}, + {'2', 1, 2}, + {'3', 1, 3}, + {'4', 1, 4}, + {'5', 1, 5}, + {'6', 1, 6}, + {'7', 1, 7}, + {'8', 1, 8}, + {'9', 1, 9}, + {'a', 1, 10}, + {'b', 1, 11}, + {'c', 1, 12}, + {'d', 1, 13}, + {'e', 1, 14}, + {'f', 1, 15}, + {'A', 1, 10}, + {'B', 1, 11}, + {'C', 1, 12}, + {'D', 1, 13}, + {'E', 1, 14}, + {'F', 1, 15}, + {'\0', 2, 0}, /* Type 2 -- end of input */ + }; + + /* + * State table + */ + static struct { + int action; + int state; + } state_table[3][3] = { + /* Period Hex End */ + { { 0, 0 }, { 1, 1 }, { 2, 0} }, /* Init */ + { { 4, 0 }, { 3, 2 }, { 4, 0} }, /* C1 */ + { { 0, 2 }, { 1, 1 }, { 2, 0} }, /* C2 */ + }; + + /* + * Initialize + */ + state = 0; + out_len = 0; + if (!strncasecmp(in, "0x", 2)) { + in += 2; + } + + /* + * Loop through input until state table says to return + */ + while (1) { + /* + * Get the character type and value + */ + for (i=0; char_table[i].c; i++) + if (char_table[i].c == *in) + break; + if (char_table[i].c != *in) + return(0); + c_type = char_table[i].type; + c_value = char_table[i].value; + + /* + * Process next character based on state and type + */ + switch(state_table[state][c_type].action) { + case 0: + /* + * Ignore the character + */ + break; + + case 1: + /* + * Save the character's value + */ + val = c_value; + break; + + case 2: + /* + * Return the assembled NSAP + */ + return(out_len); + + case 3: + /* + * Assemble and save the output byte + */ + val = val << 4; + val += c_value; + out[out_len] = (u_char) val; + out_len++; + break; + + case 4: + /* + * Invalid input sequence + */ + return(0); + + default: + return(0); + } + + /* + * Set the next state and go on to the next character + */ + state = state_table[state][c_type].state; + in++; + } +} + + +/* + * Format an ATM address into a string + * + * Arguments: + * addr pointer to an atm address + * + * Returns: + * none + * + */ +char * +format_atm_addr(addr) + Atm_addr *addr; +{ + int i; + char *nsap_format; + Atm_addr_nsap *atm_nsap; + Atm_addr_e164 *atm_e164; + Atm_addr_spans *atm_spans; + Atm_addr_pvc *atm_pvc; + static char str[256]; + union { + int w; + char c[4]; + } u1, u2; + + static char nsap_format_DCC[] = "0x%02x.%02x%02x.%02x.%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x%02x%02x.%02x"; + static char nsap_format_ICD[] = "0x%02x.%02x%02x.%02x.%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x%02x%02x.%02x"; + static char nsap_format_E164[] = "0x%02x.%02x%02x%02x%02x%02x%02x%02x%02x.%02x%02x.%02x%02x.%02x%02x%02x%02x%02x%02x.%02x"; + + /* + * Clear the returned string + */ + UM_ZERO(str, sizeof(str)); + strcpy(str, "-"); + + /* + * Print format is determined by address type + */ + switch (addr->address_format) { + case T_ATM_ENDSYS_ADDR: + atm_nsap = (Atm_addr_nsap *)addr->address; + switch(atm_nsap->aan_afi) { + default: + case AFI_DCC: + nsap_format = nsap_format_DCC; + break; + case AFI_ICD: + nsap_format = nsap_format_ICD; + break; + case AFI_E164: + nsap_format = nsap_format_E164; + break; + } + sprintf(str, nsap_format, + atm_nsap->aan_afi, + atm_nsap->aan_afspec[0], + atm_nsap->aan_afspec[1], + atm_nsap->aan_afspec[2], + atm_nsap->aan_afspec[3], + atm_nsap->aan_afspec[4], + atm_nsap->aan_afspec[5], + atm_nsap->aan_afspec[6], + atm_nsap->aan_afspec[7], + atm_nsap->aan_afspec[8], + atm_nsap->aan_afspec[9], + atm_nsap->aan_afspec[10], + atm_nsap->aan_afspec[11], + atm_nsap->aan_esi[0], + atm_nsap->aan_esi[1], + atm_nsap->aan_esi[2], + atm_nsap->aan_esi[3], + atm_nsap->aan_esi[4], + atm_nsap->aan_esi[5], + atm_nsap->aan_sel); + break; + + case T_ATM_E164_ADDR: + atm_e164 = (Atm_addr_e164 *)addr->address; + for(i=0; i<addr->address_length; i++) { + sprintf(&str[strlen(str)], "%c\0", + atm_e164->aae_addr[i]); + } + break; + + case T_ATM_SPANS_ADDR: + /* + * Print SPANS address as two words, xxxx.yyyy + */ + atm_spans = (Atm_addr_spans *)addr->address; + u1.c[0] = atm_spans->aas_addr[0]; + u1.c[1] = atm_spans->aas_addr[1]; + u1.c[2] = atm_spans->aas_addr[2]; + u1.c[3] = atm_spans->aas_addr[3]; + + u2.c[0] = atm_spans->aas_addr[4]; + u2.c[1] = atm_spans->aas_addr[5]; + u2.c[2] = atm_spans->aas_addr[6]; + u2.c[3] = atm_spans->aas_addr[7]; + + if (!(u1.w == 0 && u2.w == 0)) + sprintf(str, "0x%08x.%08x", u1.w, u2.w); + break; + + case T_ATM_PVC_ADDR: + /* + * Print PVC as VPI, VCI + */ + atm_pvc = (Atm_addr_pvc *)addr->address; + sprintf(str, "%d, %d", + ATM_PVC_GET_VPI(atm_pvc), + ATM_PVC_GET_VCI(atm_pvc)); + break; + + case T_ATM_ABSENT: + default: + break; + } + + return(str); +} diff --git a/lib/libatm/cache_key.c b/lib/libatm/cache_key.c new file mode 100644 index 0000000..f0d6650 --- /dev/null +++ b/lib/libatm/cache_key.c @@ -0,0 +1,115 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: cache_key.c,v 1.1 1998/07/09 21:45:27 johnc Exp $ + * + */ + + +/* + * User Space Library Functions + * ---------------------------- + * + * SCSP cache key computation + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: cache_key.c,v 1.1 1998/07/09 21:45:27 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <sys/socket.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_ioctl.h> + +#include <md5.h> +#include "libatm.h" + + +/* + * Compute an SCSP cache key + * + * Arguments: + * ap pointer to an Atm_addr with the ATM address + * ip pointer to a struct in_addr with the IP address + * ol the required length of the cache key + * op pointer to receive cache key + * + * Returns: + * none + * + */ +void +scsp_cache_key(ap, ip, ol, op) + Atm_addr *ap; + struct in_addr *ip; + int ol; + char *op; +{ + int i, key, len; + char *cp; + char buff[32], digest[16]; + MD5_CTX context; + + /* + * Initialize + */ + UM_ZERO(buff, sizeof(buff)); + + /* + * Copy the addresses into a buffer for MD5 computation + */ + len = sizeof(struct in_addr) + ap->address_length; + if (len > sizeof(buff)) + len = sizeof(buff); + UM_COPY(ip, buff, sizeof(struct in_addr)); + UM_COPY(ap->address, &buff[sizeof(struct in_addr)], + len - sizeof(struct in_addr)); + + /* + * Compute the MD5 digest of the combined IP and ATM addresses + */ + MD5Init(&context); + MD5Update(&context, buff, len); + MD5Final(digest, &context); + + /* + * Fold the 16-byte digest to the required length + */ + UM_ZERO((caddr_t)op, ol); + for (i = 0; i < 16; i++) { + op[i % ol] = op[i % ol] ^ digest[i]; + } +} diff --git a/lib/libatm/ioctl_subr.c b/lib/libatm/ioctl_subr.c new file mode 100644 index 0000000..a77d79f --- /dev/null +++ b/lib/libatm/ioctl_subr.c @@ -0,0 +1,515 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: ioctl_subr.c,v 1.2 1998/07/10 17:09:20 root Exp $ + * + */ + +/* + * User Space Library Functions + * ---------------------------- + * + * IOCTL subroutines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: ioctl_subr.c,v 1.2 1998/07/10 17:09:20 root Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.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_ioctl.h> + +#include "libatm.h" + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +extern char *prog; + + +/* + * Issue an informational IOCTL + * + * The user fills out the opcode and any subtype information. This + * routine will allocate a buffer and issue the IOCTL. If the request + * fails because the buffer wasn't big enough, this routine will double + * the buffer size and retry the request repeatedly. The buffer must + * be freed by the caller. + * + * Arguments: + * req pointer to an ATM information request IOCTL structure + * buf_len length of buffer to be allocated + * + * Returns: + * -1 error encountered (reason in errno) + * int length of the returned VCC information + * + */ +int +do_info_ioctl(req, buf_len) + struct atminfreq *req; + int buf_len; +{ + int rc, s; + caddr_t buf; + + /* + * Open a socket for the IOCTL + */ + s = socket(AF_ATM, SOCK_DGRAM, 0); + if (s < 0) { + return(-1); + } + + /* + * Get memory for returned information + */ +mem_retry: + buf = (caddr_t)UM_ALLOC(buf_len); + if (buf == NULL) { + errno = ENOMEM; + return(-1); + } + + /* + * Set the buffer address and length in the request + */ + req->air_buf_addr = buf; + req->air_buf_len = buf_len; + + /* + * Issue the IOCTL + */ + rc = ioctl(s, AIOCINFO, (caddr_t)req); + if (rc) { + UM_FREE(buf); + if (errno == ENOSPC) { + buf_len = buf_len * 2; + goto mem_retry; + } + return(-1); + } + (void)close(s); + /* + * Set a pointer to the returned info in the request + * and return its length + */ + req->air_buf_addr = buf; + return(req->air_buf_len); +} + + +/* + * Get VCC information + * + * Arguments: + * intf pointer to interface name (or null string) + * vccp pointer to a pointer to a struct air_vcc_rsp for the + * address of the returned VCC information + * + * Returns: + * int length of the retuned VCC information + * + */ +int +get_vcc_info(intf, vccp) + char *intf; + struct air_vcc_rsp **vccp; +{ + int buf_len = sizeof(struct air_vcc_rsp) * 100; + struct atminfreq air; + + /* + * Initialize IOCTL request + */ + air.air_opcode = AIOCS_INF_VCC; + UM_ZERO(air.air_vcc_intf, sizeof(air.air_vcc_intf)); + if (intf != NULL && strlen(intf) != 0) + strcpy(air.air_vcc_intf, intf); + + buf_len = do_info_ioctl(&air, buf_len); + + /* + * Return a pointer to the VCC info and its length + */ + *vccp = (struct air_vcc_rsp *) air.air_buf_addr; + return(buf_len); +} + + +/* + * Count number of open VCCs + * + * Issue a AIOCS_INF_VCC to get info on all open VCCs. Count them and + * return the answer. + * + * Arguments: + * intf pointer to interface name (or null string) + * + * Returns: + * int number of VCCs + * + */ +int +count_vccs ( intf ) +char *intf; +{ + int vcc_info_len; + int count = 0; + char *cp; + struct air_vcc_rsp *vcc_info, *vcc_info_base; + + vcc_info_len = get_vcc_info ( intf, &vcc_info ); + if ( !vcc_info ) + return ( 0 ); + vcc_info_base = vcc_info; + + for ( ; vcc_info_len >= sizeof ( struct air_vcc_rsp ); + vcc_info_len -= sizeof ( struct air_vcc_rsp ), + vcc_info++ ) { + count++; + } + free ( vcc_info_base ); + return ( count ); +} + + +/* + * Get subnet mask + * + * Arguments: + * intf pointer to an interface name + * mask pointer to a struct sockaddr_in to receive the mask + * + * Returns: + * 0 good completion + * -1 error + * + */ +int +get_subnet_mask(intf, mask) + char *intf; + struct sockaddr_in *mask; +{ + int rc, s; + struct ifreq req; + struct sockaddr_in *ip_mask; + + /* + * Check parameters + */ + if (!intf || !mask || + strlen(intf) == 0 || + strlen(intf) > IFNAMSIZ-1) + return(-1); + + /* + * Open a socket for the IOCTL + */ + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) + return(-1); + + /* + * Set up and issue the IOCTL + */ + UM_ZERO(&req, sizeof(req)); + strcpy(req.ifr_name, intf); + rc = ioctl(s, SIOCGIFNETMASK, (caddr_t)&req); + (void)close(s); + if (rc) + return(-1); + + /* + * Give the answer back to the caller + */ + ip_mask = (struct sockaddr_in *)&req.ifr_addr; + *mask = *ip_mask; + mask->sin_family = AF_INET; + + return(0); +} + + +/* + * Get an interface's MTU + * + * Arguments: + * intf pointer to an interface name + * mtu pointer to an int to receive the MTU + * + * Returns: + * >= 0 interface MTU + * -1 error + * + */ +int +get_mtu(intf) + char *intf; +{ + int rc, s; + struct ifreq req; + + /* + * Check parameters + */ + if (!intf || strlen(intf) == 0 || + strlen(intf) > IFNAMSIZ-1) + return(-1); + + /* + * Open a socket for the IOCTL + */ + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s < 0) + return(-1); + + /* + * Set up and issue the IOCTL + */ + UM_ZERO(&req, sizeof(req)); + strcpy(req.ifr_name, intf); + rc = ioctl(s, SIOCGIFMTU, (caddr_t)&req); + (void)close(s); + + /* + * Set the appropriate return value + */ + if (rc) + return(-1); + else + return(req.ifr_mtu); +} + + +/* + * Verify netif name + * + * This routine issues an IOCTL to check whether the passed string is + * a valid network interface name. + * + * Arguments: + * req pointer to an ATM information request IOCTL structure + * + * Returns: + * -1 error encountered + * FALSE (0) the string is not a NIF name + * TRUE (> 0) the string is a valid NIF name + * + */ +int +verify_nif_name(name) + char *name; +{ + int rc, s; + caddr_t buf; + struct atminfreq air; + struct air_netif_rsp *nif_info; + + /* + * Check whether name is of a valid length + */ + if (strlen(name) > IFNAMSIZ - 1 || + strlen(name) < 1) { + return(FALSE); + } + + /* + * Open a socket for the IOCTL + */ + s = socket(AF_ATM, SOCK_DGRAM, 0); + if (s < 0) { + return(-1); + } + + /* + * Get memory for returned information + */ + nif_info = (struct air_netif_rsp *)UM_ALLOC( + sizeof(struct air_netif_rsp)); + if (nif_info == NULL) { + errno = ENOMEM; + return(-1); + } + + /* + * Set up the request + */ + air.air_opcode = AIOCS_INF_NIF; + air.air_buf_addr = (caddr_t)nif_info; + air.air_buf_len = sizeof(struct air_netif_rsp); + UM_ZERO(air.air_netif_intf, sizeof(air.air_netif_intf)); + strcpy(air.air_netif_intf, name); + + /* + * Issue the IOCTL + */ + rc = ioctl(s, AIOCINFO, (caddr_t)&air); + UM_FREE(nif_info); + (void)close(s); + + /* + * Base return value on IOCTL return code + */ + if (rc) + return(FALSE); + else + return(TRUE); +} + +/* + * Get Config information + * + * Arguments: + * intf pointer to interface name (or null string) + * cfgp pointer to a pointer to a struct air_cfg_rsp for the + * address of the returned Config information + * + * Returns: + * int length of returned Config information + * + */ +int +get_cfg_info ( intf, cfgp ) + char *intf; + struct air_cfg_rsp **cfgp; +{ + int buf_len = sizeof(struct air_cfg_rsp) * 4; + struct atminfreq air; + + /* + * Initialize IOCTL request + */ + air.air_opcode = AIOCS_INF_CFG; + UM_ZERO ( air.air_cfg_intf, sizeof(air.air_cfg_intf)); + if ( intf != NULL && strlen(intf) != 0 ) + strcpy ( air.air_cfg_intf, intf ); + + buf_len = do_info_ioctl ( &air, buf_len ); + + /* + * Return a pointer to the Config info and its length + */ + *cfgp = (struct air_cfg_rsp *) air.air_buf_addr; + return ( buf_len ); + +} + +/* + * Get Physical Interface information + * + * Arguments: + * intf pointer to interface name (or null string) + * intp pointer to a pointer to a struct air_cfg_rsp for the + * address of the returned Config information + * + * Returns: + * int length of returned Config information + * + */ +int +get_intf_info ( intf, intp ) + char *intf; + struct air_int_rsp **intp; +{ + int buf_len = sizeof(struct air_int_rsp) * 4; + struct atminfreq air; + + /* + * Initialize IOCTL request + */ + air.air_opcode = AIOCS_INF_INT; + UM_ZERO ( air.air_int_intf, sizeof(air.air_int_intf)); + if ( intf != NULL && strlen(intf) != 0 ) + strcpy ( air.air_int_intf, intf ); + + buf_len = do_info_ioctl ( &air, buf_len ); + + /* + * Return a pointer to the Physical Interface info and its length + */ + *intp = (struct air_int_rsp *) air.air_buf_addr; + return ( buf_len ); + +} + + +/* + * Get Netif information + * + * Arguments: + * intf pointer to interface name (or null string) + * netp pointer to a pointer to a struct air_netif_rsp for the + * address of the returned Netif information + * + * Returns: + * int length of returned Netif information + * + */ +int +get_netif_info ( intf, netp ) + char *intf; + struct air_netif_rsp **netp; +{ + int buf_len = sizeof(struct air_netif_rsp) * 10; + struct atminfreq air; + + /* + * Initialize IOCTL request + */ + air.air_opcode = AIOCS_INF_NIF; + UM_ZERO ( air.air_int_intf, sizeof(air.air_int_intf) ); + if ( intf != NULL && strlen(intf) != 0 ) + strcpy ( air.air_int_intf, intf ); + + buf_len = do_info_ioctl ( &air, buf_len ); + + /* + * Return a pointer to the Netif info and its length + */ + *netp = (struct air_netif_rsp *) air.air_buf_addr; + return ( buf_len ); + +} + + diff --git a/lib/libatm/ip_addr.c b/lib/libatm/ip_addr.c new file mode 100644 index 0000000..aee3368 --- /dev/null +++ b/lib/libatm/ip_addr.c @@ -0,0 +1,167 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: ip_addr.c,v 1.1 1998/07/09 21:45:42 johnc Exp $ + * + */ + +/* + * User Space Library Functions + * ---------------------------- + * + * IP address utilities + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: ip_addr.c,v 1.1 1998/07/09 21:45:42 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <netdb.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <arpa/inet.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_ioctl.h> + +#include "libatm.h" + + +/* + * Get IP address + * + * Return an IP address in a socket address structure, given a character + * string with a domain name or a dotted decimal number. + * + * Arguments: + * p pointer to a host name or IP address + * + * Returns: + * null error was encountered + * struct sockaddr_in * a pointer to a socket address with the + * requested IP address + * + */ +struct sockaddr_in * +get_ip_addr(p) + char *p; +{ + struct hostent *ip_host; + static struct sockaddr_in sin; + + /* + * Get IP address of specified host name + */ + UM_ZERO(&sin, sizeof(sin)); + sin.sin_family = AF_INET; + if (p[0] >= '0' && p[0] <= '9') { + /* + * IP address is in dotted decimal format + */ + if ((sin.sin_addr.s_addr = inet_addr(p)) == -1) { + return((struct sockaddr_in *)0); + } + } else { + /* + * Host name is in domain name system format + */ + ip_host = gethostbyname(p); + if (!ip_host || + ip_host->h_addrtype != AF_INET) { + return((struct sockaddr_in *)0); + } + sin.sin_addr.s_addr = *(u_long *)ip_host->h_addr_list[0]; + } + return(&sin); +} + + +/* + * Format an IP address + * + * Return a text-formatted string with an IP address and domain name + * given a sockaddr_in with an IP address. + * + * Arguments: + * p pointer to sockaddr_in with an IP address + * + * Returns: + * char * pointer to a text-formatted string + * + */ +char * +format_ip_addr(addr) + struct in_addr *addr; +{ + static char host_name[128]; + char *ip_num; + struct hostent *ip_host; + + /* + * Initialize + */ + UM_ZERO(host_name, sizeof(host_name)); + + /* + * Check for a zero address + */ + if (!addr || addr->s_addr == 0) { + return("-"); + } + + /* + * Get address in dotted decimal format + */ + ip_num = inet_ntoa(*addr); + + /* + * Look up name in DNS + */ + ip_host = gethostbyaddr((char *)addr, sizeof(addr), AF_INET); + if (ip_host && ip_host->h_name && + strlen(ip_host->h_name)) { + /* + * Return host name followed by dotted decimal address + */ + strcpy(host_name, ip_host->h_name); + strcat(host_name, " ("); + strcat(host_name, ip_num); + strcat(host_name, ")"); + return(host_name); + } else { + /* + * No host name -- just return dotted decimal address + */ + return(ip_num); + } +} diff --git a/lib/libatm/ip_checksum.c b/lib/libatm/ip_checksum.c new file mode 100644 index 0000000..478f6ca --- /dev/null +++ b/lib/libatm/ip_checksum.c @@ -0,0 +1,102 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: ip_checksum.c,v 1.4 1998/08/11 18:11:48 johnc Exp $ + * + */ + + +/* + * User Space Library Functions + * ---------------------------- + * + * IP checksum computation + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: ip_checksum.c,v 1.4 1998/08/11 18:11:48 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <sys/socket.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_ioctl.h> + +#include "libatm.h" + + +/* + * Compute an IP checksum + * + * This code was taken from RFC 1071. + * + * "The following "C" code algorithm computes the checksum with an inner + * loop that sums 16 bits at a time in a 32-bit accumulator." + * + * Arguments: + * addr pointer to the buffer whose checksum is to be computed + * count number of bytes to include in the checksum + * + * Returns: + * the computed checksum + * + */ +short +ip_checksum(addr, count) + char *addr; + int count; +{ + /* Compute Internet Checksum for "count" bytes + * beginning at location "addr". + */ + register long sum = 0; + + while( count > 1 ) { + /* This is the inner loop */ + sum += ntohs(* (unsigned short *) addr); + addr += sizeof(unsigned short); + count -= sizeof(unsigned short); + } + + /* Add left-over byte, if any */ + if( count > 0 ) + sum += * (unsigned char *) addr; + + /* Fold 32-bit sum to 16 bits */ + while (sum>>16) + sum = (sum & 0xffff) + (sum >> 16); + + return((short)~sum); +} diff --git a/lib/libatm/libatm.h b/lib/libatm/libatm.h new file mode 100644 index 0000000..3462431 --- /dev/null +++ b/lib/libatm/libatm.h @@ -0,0 +1,118 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: libatm.h,v 1.5 1998/08/06 16:56:27 johnc Exp $ + * + */ + +/* + * User Space Library Functions + * ---------------------------- + * + * Library functions + * + */ + +#ifndef _HARP_LIBHARP_H +#define _HARP_LIBHARP_H + +/* + * Start a HARP user-space timer + * + * tp pointer to timer control block + * time number of seconds for timer to run + * fp pointer to function to call at expiration + */ +#define HARP_TIMER(tp, time, fp) \ +{ \ + (tp)->ht_ticks = (time); \ + (tp)->ht_mark = 0; \ + (tp)->ht_func = (fp); \ + LINK2HEAD((tp), Harp_timer, harp_timer_head, ht_next); \ +} + +/* + * Cancel a HARP user-space timer + * + * tp pointer to timer control block + */ +#define HARP_CANCEL(tp) \ +{ \ + UNLINK((tp), Harp_timer, harp_timer_head, ht_next); \ +} + + +/* + * HARP user-space timer control block + */ +struct harp_timer { + struct harp_timer *ht_next; /* Timer chain */ + int ht_ticks; /* Seconds till exp */ + int ht_mark; /* Processing flag */ + void (*ht_func)(); /* Function to call */ +}; +typedef struct harp_timer Harp_timer; + + +/* + * Externally-visible variables and functions + */ + +/* atm_addr.c */ +extern int get_hex_atm_addr __P((char *, u_char *, int)); +extern char *format_atm_addr __P((Atm_addr *)); + +/* cache_key.c */ +extern void scsp_cache_key __P((Atm_addr *, + struct in_addr *, int, char *)); + +/* ioctl_subr.c */ +extern int do_info_ioctl __P((struct atminfreq *, int)); +extern int get_vcc_info __P((char *, + struct air_vcc_rsp **)); +extern int get_subnet_mask __P((char *, + struct sockaddr_in *)); +extern int get_mtu __P((char *)); +extern int verify_nif_name __P((char *)); +extern int get_cfg_info __P((char *, + struct air_cfg_rsp **)); + +/* ip_addr.c */ +extern struct sockaddr_in *get_ip_addr __P((char *)); +extern char *format_ip_addr __P((struct in_addr *)); + +/* ip_checksum.c */ +extern short ip_checksum __P((char *, int)); + +/* timer.c */ +extern Harp_timer *harp_timer_head; +extern int harp_timer_exec; +extern void timer_proc __P(()); +extern int init_timer __P(()); +extern int block_timer __P(()); +extern void enable_timer __P((int)); + + +#endif /* _HARP_LIBHARP_H */ diff --git a/lib/libatm/timer.c b/lib/libatm/timer.c new file mode 100644 index 0000000..fc8b64f --- /dev/null +++ b/lib/libatm/timer.c @@ -0,0 +1,261 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: timer.c,v 1.4 1998/07/16 15:50:26 johnc Exp $ + * + */ + +/* + * User Space Library Functions + * ---------------------------- + * + * Timer functions + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: timer.c,v 1.4 1998/07/16 15:50:26 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include "libatm.h" + +Harp_timer *harp_timer_head; +int harp_timer_exec; + + +/* + * Process a HARP timer tick + * + * This function is called via the SIGALRM signal. It increments + * harp_timer_exec. The user should check this flag frequently and + * call timer_proc when it is set. + * + * Arguments: + * None + * + * Returns: + * None + * + */ +static void +timer_tick() +{ + /* + * Bump the timer flag + */ + harp_timer_exec++; +} + + +/* + * Process HARP timers + * + * This function is called after a SIGALRM signal is posted. It runs + * down the list of timer entries, calling the specified functions + * for any timers that have expired. + * + * Arguments: + * None + * + * Returns: + * None + * + */ +void +timer_proc() +{ + Harp_timer *htp; + void (*f)(); + + /* + * Reset marks in all timers on the queue + */ + for (htp = harp_timer_head; htp; htp = htp->ht_next) { + htp->ht_mark = -1; + } + + /* + * Run through timer chain decrementing each timer. + * If an expired timer is found, take the timer block + * off the chain and call the specified function. A + * timer's action can result in other timers being + * cancelled (taken off the queue), so every time we + * call a user function, we start over from the top of + * the list. + */ +timer_cont: + for (htp = harp_timer_head; htp; htp = htp->ht_next) { + /* + * Make sure we only process each entry once and + * don't process entries that are put on the queue + * by user functions we call for this tick + */ + if (htp->ht_mark == -1) { + /* + * Decrement the timer and mark that we've + * processed the entry + */ + htp->ht_ticks -= harp_timer_exec; + htp->ht_mark = 1; + + /* + * Check whether the timer is expired + */ + if (htp->ht_ticks <= 0) { + /* + * Unlink the timer block and call + * the user function + */ + f = htp->ht_func; + UNLINK(htp, Harp_timer, harp_timer_head, + ht_next); + f(htp); + + /* + * Start over + */ + goto timer_cont; + } + } + } + + /* + * Reset the timer exec flag + */ + harp_timer_exec = 0; +} + + +/* + * Start the timer + * + * Set up the SIGALRM signal handler and set up the real-time + * timer to tick once per second. + * + * Arguments: + * None + * + * Returns: + * 0 success + * errno reason for failure + * + */ +int +init_timer() +{ + int rc = 0; + struct itimerval timeval; + + /* + * Clear the timer flag + */ + harp_timer_exec = 0; + + /* + * Set up signal handler + */ + if ((int)signal(SIGALRM, timer_tick) == -1) { + return(errno); + } + + /* + * Start timer + */ + timeval.it_value.tv_sec = 1; + timeval.it_value.tv_usec = 0; + timeval.it_interval.tv_sec = 1; + timeval.it_interval.tv_usec = 0; + + if (setitimer(ITIMER_REAL, &timeval, + (struct itimerval *)0) == -1) { + rc = errno; + (void)signal(SIGALRM, SIG_DFL); + } + + return(rc); +} + + +/* + * Block timers from firing + * + * Block the SIGALRM signal. + * + * Arguments: + * None + * + * Returns: + * mask the previous blocked signal mask + * + */ +int +block_timer() +{ + /* + * Block the SIGALRM signal + */ + return(sigblock(sigmask(SIGALRM))); +} + + +/* + * Re-enable timers + * + * Restore the signal mask (presumably one that was returned by + * block_timer). + * + * Arguments: + * mask the signal mask to be restored + * + * Returns: + * mask the previous blocked signal mask + * + */ +void +enable_timer(mask) + int mask; +{ + /* + * Set the signal mask + */ + sigsetmask(mask); + + return; +} diff --git a/sbin/atm/Makefile b/sbin/atm/Makefile new file mode 100644 index 0000000..481f216 --- /dev/null +++ b/sbin/atm/Makefile @@ -0,0 +1,33 @@ +# +# +# =================================== +# 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. +# +# @(#) $Id: Makefile,v 1.5 1998/07/10 16:01:58 jpt Exp $ +# + +SUBDIR= atm \ + fore_dnld \ + ilmid + +.include <bsd.subdir.mk> diff --git a/sbin/atm/Makefile.inc b/sbin/atm/Makefile.inc new file mode 100644 index 0000000..2bf6722 --- /dev/null +++ b/sbin/atm/Makefile.inc @@ -0,0 +1,30 @@ +# +# +# =================================== +# 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. +# +# @(#) $Id: Makefile.inc,v 1.5 1998/07/10 16:01:58 jpt Exp $ +# +# + +.include "${.CURDIR}/../../Makefile.inc" diff --git a/sbin/atm/atm/Makefile b/sbin/atm/atm/Makefile new file mode 100644 index 0000000..18c02db --- /dev/null +++ b/sbin/atm/atm/Makefile @@ -0,0 +1,38 @@ +# +# +# =================================== +# 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. +# +# @(#) $Id: Makefile,v 1.5 1998/07/10 16:01:58 jpt Exp $ +# +# + +PROG= atm +SRCS= atm.c atm_fore200.c atm_eni.c atm_inet.c atm_print.c \ + atm_set.c atm_show.c atm_subr.c +MAN8= atm.8 + +CFLAGS+= -I ${.CURDIR}/../../../sys +LDADD+= -latm + +.include <bsd.prog.mk> diff --git a/sbin/atm/atm/atm.8 b/sbin/atm/atm/atm.8 new file mode 100644 index 0000000..51b39f9 --- /dev/null +++ b/sbin/atm/atm/atm.8 @@ -0,0 +1,984 @@ +.\" +.\" =================================== +.\" 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. +.\" +.\" @(#) $Id: atm.1,v 1.4 1998/08/26 21:38:28 johnc Exp $ +.\" +.\" +.de EX \"Begin example +.ne 5 +.if n .sp 1 +.if t .sp .5 +.nf +.in +.5i +.. +.de EE +.fi +.in -.5i +.if n .sp 1 +.if t .sp .5 +.. +.TH ATM 8 "1998-08-20" "HARP" +.SH NAME +atm \- user configuration and display command for HARP ATM interface +.SH SYNOPSIS +Interface management subcommands: +.in +10 +.ti -5 +.B atm attach +<interface> <sigmgr> +.ti -5 +.B atm detach +<interface> +.ti -5 +.B atm set MAC +<interface> <MAC/ESI address> +.ti -5 +.B atm set netif +<interface> <prefix> <count> +.ti -5 +.B atm set prefix +<interface> <NSAP prefix> +.ti -5 +.B atm show config +[<interface>] +.ti -5 +.B atm show interface +[<interface>] +.ti -5 +.B atm show netif +[<netif>] +.ti -5 +.B atm show stats interface +[<interface> [phy | dev | atm | aal0 | aal4 | aal5 | driver]] +.sp +.ti -10 +VCC management subcommands: +.ti -5 +.B atm add PVC +<interface> <vpi> <vci> <aal> <encaps> <owner> ... +.ti -5 +.B atm delete PVC +<interface> <vpi> <vci> +.ti -5 +.B atm delete SVC +<interface> <vpi> <vci> +.ti -5 +.B atm show stats VCC +[<interface> [<vpi> [<vci>]]] +.ti -5 +.B atm show VCC +[<interface> [<vpi> [<vci>] | SVC | PVC]] +.sp +.ti -10 +IP management subcommands: +.ti -5 +.B atm add ARP +[<netif>] <host> <ATM address> +.ti -5 +.B atm add PVC +<interface> <vpi> <vci> <aal> <encaps> IP <netif> <host> | dynamic +.ti -5 +.B atm delete ARP +[<netif>] <host> +.ti -5 +.B atm set arpserver +<netif> <ATM address> | local [<IP prefix> ...] +.ti -5 +.B atm show ARP +[<host>] +.ti -5 +.B atm show arpserver +[<netif>] +.ti -5 +.B atm show IPVCC +[<host> | <netif>] +.ti -5 +.sp +.ti -10 +Miscellaneous subcommands: +.ti -5 +.B atm help +.ti -5 +.B atm show version +.in -10 +.fi +.SH DESCRIPTION +.I atm +configures and displays the status of the Host ATM Research Platform +(HARP) networking software. +The subcommands fall into several categories: +.PP +\fIInterface management\fP subcommands allow manipulation of the +ATM interface. +Functions include assigning a signalling manager to an interface, +setting the ATM address, associating network interfaces with +an interface, and displaying information about interfaces. +.PP +\fIVCC management\fP subcommands allow for managing ATM virtual +channel connections (VCCs). +Functions include opening and closing VCCs and displaying information +about them. +.PP +\fIIP management\fP subcommands allow for managing the interface +between IP and the ATM software. +Functions include displaying and manipulating the ATMARP cache, +opening a PVC connected to IP, +assigning an ATMARP server to a network interface, +and displaying information about IP VCCs. +.PP +\fIMiscellaneous\fP subcommands allow for displaying the version +of the ATM software and for getting help with the \fIatm\fP command. +.SS "Signalling Managers" +The signalling manager is responsible for the opening and closing of +VCCs. +Four signalling managers are supported: +.PP +.in +10 +.ti -5 +PVC - for PVCs only, +.ti -5 +SPANS - supports SPANS, FORE's proprietary signalling protocol, +.ti -5 +UNI 3.0 - supports the signalling protocol from The ATM Forum's +\fIATM User-Network Interface Specification, Version 3.0\fP. +.ti -5 +UNI 3.1 - supports the signalling protocol from The ATM Forum's +\fIATM User-Network Interface Specification, Version 3.1\fP. +.in -10 +.PP +All four signalling managers support the opening and closing of PVCs +(see the \fIadd\fP and \fIdelete\fP subcommands). +.PP +A signalling manager must be attached to a physical interface +(see the \fIattach\fP subcommand) +before any VCCs can be created on the interface. +.SS "Physical and Network Interfaces" +Two types of interfaces are supported: +physical interfaces and network interfaces. +A physical interface represents a physical point of attachment to an +ATM network. +A physical interface has an ATM address associated with it. +.PP +A network interface is a logical interface. +One or more network interfaces are associated with a physical +interface; each network interface has an IP address associated with it. +For interfaces controlled by the SPANS or PVC signalling managers, +there must be one and +only one network interface associated with each physical interface. +For UNI-controlled interfaces, there can be up to 256 network +interfaces associated with a physical interface. +In this case, the correspondence between the network interface and +the ATM address is determined by the selector field (the last +byte) of the physical interface's ATM address. +.SS "Keyword and Documentation Conventions" +Command and subcommand keywords can be abbreviated by simply giving +enough of the first part of the keyword to make it unique. +Thus, \fIatm sh v\fB gives the same result as \fIatm show vcc\fB. +.PP +All keywords are case-insensitive. +.PP +Where a host address needs to be given to the \fIatm\fP command, +either a DNS name or an IP address in dotted decimal format can +be used. +.PP +ATM addresses are specified as strings of hex digits, with an +optional leading "0x". +Fields within the address may be separated by periods, but periods +are for readability only and are ignored. +SPANS addresses are 8 bytes long, while NSAP-format addresses +are 20 bytes long. +The full address, including any leading zeroes, must be given. +For example: +.in +5 +0x47.0005.80.ffe100.0000.f21a.0170.0020481a0170.00 (NSAP format) +.br +0x00000010.f2050aa9 (SPANS format) +.in -5 +.fi +.SH SUBCOMMANDS +.SS Interface Management Subcommands: +.in +5 +.ti -5 +\fIatm add PVC <interface> <vpi> <vci> <aal> <encaps> <owner> ...\fP +.in -5 +.PP +the format of the \fIadd PVC\fP subcommand varies depending on the +owner of the PVC. +See the description under "IP Management Subcommands." +.PP +\fIatm attach <interface> <sigmgr>\fP +.PP +where: +.in +10 +.ti -5 +\fI<interface>\fP specifies the physical interface to which the +signalling manager is to be attached, +.ti -5 +\fI<sigmgr>\fP specifies which signalling manager is to be attached. +Valid choices are "SIGPVC", "SPANS", "UNI30", and "UNI31". +.in -10 +.PP +This command attaches a signalling manager to an interface. +Until this is done, VCCs cannot be opened or closed. +Only one signalling manager at a time can be attached to an interface. +.PP +\fIatm detach <interface>\fP +.PP +where: +.in +10 +.ti -5 +\fI<interface>\fP specifies the physical interface whose signalling +manager is to be detached. +.in -10 +.PP +This command detaches a signalling manager from an interface. +All VCCs that the signalling manager has created will be closed, +and no new VCCs can be created until a signalling manager (either +the same or a different one) is attached again. +.PP +\fIatm set MAC <interface> <MAC/ESI address>\fP +.PP +where: +.in +10 +.ti -5 +\fI<interface>\fP specifies the physical interface whose +MAC address is to be set, +.ti -5 +\fI<MAC/ESI address>\fP specifies the 6-byte MAC part of the NSAP +address for the interface. +The MAC address is specified as a string of 12 hexadecimal +digits with an optional leading "0x". +Fields in the address may be separated by periods. +.in -10 +.PP +This command sets the MAC address for a UNI-controlled interface. +The first 13 bytes (the prefix) of the 20-byte NSAP-format address +are set by the \fIatm set prefix\fP command or the ILMI daemon +(\fIilmid\fP (8)), +the next 6 bytes (the End System Identifier (ESI)) are set by +this command, +and the last byte (the selector) will be determined by which +network interface is to be associated with the address. +.PP +The \fIatm set MAC\fP command can be used to override the MAC +address in the interface hardware. +.PP +\fIatm set netif <interface> <prefix> <count>\fP +.PP +where: +.in +10 +.ti -5 +\fI<interface>\fP specifies the physical interface that the network +interface(s) are to be associated with, +.ti -5 +\fI<prefix>\fP specifies the invariant part of the network +interface name, +.ti -5 +\fI<count>\fP specifies the number of network interface to be +created. +.in -10 +.PP +This command creates one or more network interfaces and associates them +with the specified physical interface. +The network interface names are determined by the prefix and the count. +The names will be of the form <prefix><nn>, where <prefix> is the +prefix specified in the \fIset\fP subcommand and <nn> is a number +in the range 0 - <count>-1. For example, the command: +.PP +.ti +5 +atm set netif hfa0 ni 2 +.PP +would create two network interfaces, named ni0 and ni1, and associate +them with physical interface hfa0. +.PP +\fIatm set prefix <interface> <NSAP prefix>\fP +.PP +where: +.in +10 +.ti -5 +\fI<interface>\fP specifies the physical interface whose NSAP +prefix is to be set, +.ti -5 +\fI<NSAP prefix>\fP specifies the first 13 bytes of the NSAP address +for the interface. +The prefix is specified as a string of hexadecimal digits with an +optional leading "0x". +Fields in the prefix may be separated by periods. +.in -10 +.PP +This command sets the address for a UNI-controlled interface. +The first 13 bytes (the prefix) of the 20-byte NSAP-format address +are set by this command, +the next 6 bytes (the End System Identifier (ESI)) will be the +MAC address taken from the physical interface or set by the +\fIset MAC\fP subcommand, +and the last byte (the selector) will be determined by which +network interface is to be associated with the address. +.PP +The NSAP prefix must be set before a UNI-controlled +interface can become active. +This can be accomplished either by the ILMI daemon (\fIilmid\fP (8)) +or the \fIset prefix\fP subcommand. +.PP +.I atm show config [<interface>] +.PP +displays the following information: +.PP +.B Interface +\- the name of the physical interface. +.PP +.B Vendor +\- the name of the adapter vendor. +.PP +.B Model +\- the model of the adapter. +.PP +.B Media +\- the communications medium used by the adapter. +.PP +.B Bus +\- the type of bus the adapter is attached to. +.PP +.B Serial No. +\- the adapter's serial number. +.PP +.B MAC address +\- the MAC address of the interface. +Note that this is the MAC address encoded in the hardware of +the adapter, even if the \fIatm set MAC\fP command has been used +to change the effective MAC address of the interface. +.PP +.B Hardware version +\- the hardware revision level reported by the interface. +.PP +.B Firmware version +\- the firmware revision level reported by the interface. +.PP +If no parameters are specified on the \fIshow config\fP subcommand, +the configurations of all physical interfaces will be displayed. +If an interface name is specified, only the configuration of the given +interface is displayed. +.PP +.I atm show interface [<interface>] +.PP +displays the following information: +.PP +.B Interface +\- the name of the physical interface. +.PP +.B Sigmgr +\- the name of the signalling manager which has been attached to the +interface. +A dash (-) is shown if no signalling manager has been attached. +.PP +.B State +\- the state of the signalling manager for the interface. +Each signalling manager has its own set of states. +They are: +.in +21 +.ti -16 +PVC: +.ti -11 +ACTIVE\ ---\ The signalling manager is active. +.ti -11 +DETACH\ ---\ The signalling manager is being detached. +.ti -16 +SPANS: +.ti -11 +ACTIVE\ ---\ The signalling manager is active. +.ti -11 +DETACH\ ---\ The signalling manager is being detached. +.ti -11 +INIT\ -----\ The signalling manager's initial state. +.ti -11 +PROBE\ ----\ The signalling manager is attempting to make +contact with the ATM switch. +.ti -16 +UNI 3.0 or UNI 3.1: +.ti -11 +NULL\ -----\ The signalling manager's initial state. +.ti -11 +ADR_WAIT\ -\ The signalling manager is waiting for the NSAP +prefix to be set. +.ti -11 +INIT\ -----\ The signalling manager is attempting to establish +contact with the switch. +.ti -11 +ACTIVE\ ---\ The signalling manager is active. +.ti -11 +DETACH\ ---\ The signalling manager is being detached. +.ti -21 +.PP +.B ATM address +\- the ATM address of the interface. +.PP +.B Network interfaces +\- the names of network interfaces, if any, associated with the +physical interface. +.PP +If no parameters are specified on the \fIshow interface\fP subcommand, +information about all physical interfaces will be displayed. +If an interface name is specified, only information about the given +interface is displayed. +.PP +.I atm show netif [<netif>] +.PP +displays the following information: +.PP +.B Net Intf +\- the name of the network interface. +.PP +.B IP Address +\- the IP address of the network interface. +.PP +If no parameters are specified on the \fIshow netif\fP subcommand, +information about all network interfaces will be displayed. +If an interface name is specified, only information about the given +network interface is displayed. +.PP +\fIatm show stats interface [<interface> [phy | dev | atm | aal0 | +aal4 | aal5 | driver]]\fP +.PP +displays statistics associated with one or more interfaces. +Subject-area keywords +(\fIphy\fP, \fIdev\fP, \fIatm\fP, \fIaal0\fP, +\fIaal4\fP, \fIaal5\fP, or \fIdriver\fP) +can be specified to change the scope of the statistics displayed. +.PP +If no subject area keyword is specified, the following information is +displayed: +.PP +.B Interface +\- the name of the physical ATM interface. +.PP +.B Input PDUs +\- the number of Protocol Data Units (PDUs) which have been received +by the interface. +.PP +.B Input Bytes +\- the number of bytes which have been received by the interface. +.PP +.B Input Errs +\- the number of input errors which the interface has experienced. +.PP +.B Output PDUs +\- the number of Protocol Data Units (PDUs) which have been transmitted +by the interface. +.PP +.B Output Bytes +\- the number of bytes which have been transmitted by the interface. +.PP +.B Output Errs +\- the number of output errors which the interface has experienced. +.PP +.B Cmd Errs +\- the number of command errors which the interface has experienced. +.PP +If a subject-area keyword is specified, then statistics for +that subject are displayed. +The statistics displayed depend on the adapter. +If requested statistics are not available for an adaptor, +an error will be noted. +.PP +If no parameters are specified on the \fIshow stats interface\fP +subcommand, statistics for all ATM interfaces are displayed. +If an interface name is specified, only statistics for the given +interface are displayed. +.PP +.SS VCC Management Subcommands: +.PP +\fIatm delete PVC <interface> <vpi> <vci>\fP +.br +\fIatm delete SVC <interface> <vpi> <vci>\fP +.PP +where: +.in +10 +.ti -5 +\fIPVC\fP specifies that the VCC to be closed is a PVC, +.ti -5 +\fISVC\fP specifies that the VCC to be closed is an SVC, +.ti -5 +\fI<interface>\fP specifies the physical interface at which the +VCC to be closed terminates, +.ti -5 +\fI<vpi>\fP specifies the Virtual Path Identifier (VPI) of the VCC, +.ti -5 +\fI<vci>\fP specifies the Virtual Channel Identifier (VCI) of the VCC. +.in -10 +.PP +This command closes a VCC. +The two forms differ only in that the first specifies that the +VCC is a PVC (that was created by the \fIadd PVC\fP subcommand) and +the second specifies that the VCC is an SVC. +Reserved VCCs (with VCI values less than 32) cannot be closed +with this command. +.PP +\fIatm show stats VCC [<interface> [<vpi> [<vci>]]]\fP +.PP +displays the following information: +.PP +.B Interface +\- the physical interface on which the VCC terminates. +.PP +.B VPI +\- the Virtual Path Identifier (VPI) for the VCC. +.PP +.B VCI +\- the Virtual Channel Identifier (VCI) for the VCC. +.PP +.B Input PDUs +\- the number of Protocol Data Units (PDUs) which have been received +on the VCC. +.PP +.B Input Bytes +\- the number of bytes which have been received on the VCC. +.PP +.B Input Errs +\- the number of input errors which the VCC has experienced. +.PP +.B Output PDUs +\- the number of Protocol Data Units (PDUs) which have been transmitted +on the VCC. +.PP +.B Output Bytes +\- the number of bytes which have been transmitted on the VCC. +.PP +.B Output Errs +\- the number of output errors which the VCC has experienced. +.PP +If no parameters are specified on the \fIshow VCC\fP subcommand, all +active VCCs are displayed. +If an interface name is specified, all active VCCs for the given +interface are displayed. +If an interface and VPI are specified, all active VCCs for the VPI +on the given interface are displayed. +If an interface, VPI, and VCI are specified, only the specified VCC on +the given interface is displayed (note that this could actually be +two VCCs, since SPANS considers SVCs to be unidirectional). +.PP +\fIatm show VCC [<interface> [<vpi> [<vci>] | SVC | PVC]]\fP +.PP +displays the following information: +.PP +.B Interface +\- the physical interface on which the VCC terminates. +.PP +.B VPI +\- the Virtual Path Identifier (VPI) for the VCC. +.PP +.B VCI +\- the Virtual Channel Identifier (VCI) for the VCC. +.PP +.B AAL +\- the ATM Adaptation Layer (AAL) in use on the VCC. +Possible values are null and AAL 1-5. +.PP +.B Type +\- specifies whether the VCC is an SVC or a PVC. +.PP +.B Dir +\- the direction of information flow on the VCC. +VCCs can be inbound, outbound, or both. +.PP +.B State +\- the state of the VCC, as reported by the signalling manager. +Each signalling manager has its own set of states. +They are: +.in +21 +.ti -16 +PVC: +.ti -11 +NULL\ -----\ No state. +.ti -11 +ACTIVE\ ---\ The VCC is active. +.ti -11 +FREE\ -----\ The VCC is closed and the signalling manager is waiting for +its resources to be freed. +.ti -16 +SPANS: +.ti -11 +NULL\ -----\ No state. +.ti -11 +ACTIVE\ ---\ The VCC is a PVC and is active. +.ti -11 +ACT_DOWN\ -\ The VCC is a PVC and the interface is down. +.ti -11 +POPEN\ ----\ The VCC is being opened. +.ti -11 +R_POPEN\ --\ The VCC is being opened by a remote host. +.ti -11 +OPEN\ -----\ The VCC is active. +.ti -11 +CLOSE\ ----\ The VCC is being closed. +.ti -11 +ABORT\ ----\ The VCC is being aborted. +.ti -11 +FREE\ -----\ The VCC is closed and the signalling manager is waiting for +its resources to be freed. +.ti -16 +UNI 3.0 or UNI 3.1: +.ti -11 +NULL\ -----\ No state. +.ti -11 +C_INIT\ ---\ A VCC is being initiated. +.ti -11 +C_OUT_PR\ -\ An outgoing VCC request is proceeding. +.ti -11 +C_PRES\ ---\ A VCC is being initiated by the network. +.ti -11 +CONN_REQ\ -\ A VCC request has been accepted by a HARP user. +.ti -11 +C_IN_PR\ --\ An incoming VCC request is proceeding. +.ti -11 +ACTIVE\ ---\ The VCC is active. +.ti -11 +REL_REQ\ --\ The VCC is being closed. +.ti -11 +REL_IND\ --\ The network is clearing a VCC. +.ti -11 +SSCF_REC\ -\ The SSCF session on the signalling channel is in +recovery from an error. +.ti -11 +FREE\ -----\ The VCC is closed and the signalling manager is waiting +for its resources to be freed. +.ti -11 +ACT_DOWN\ -\ The VCC is a PVC and the interface is down. +.ti -21 +.PP +.B Encaps +\- the encapsulation in effect on the VCC. +Possible encapsulations are null and LLC/SNAP. +.PP +.B Owner +\- the owner or owners of the VCC. +Shows the name(s) of the function(s) using the VCC. +.PP +.B Destination +\- the ATM address of the host at the remote end of the VCC. +.PP +If no parameters are specified on the \fIshow VCC\fP subcommand, all +active VCCs are displayed. +If an interface name is specified, all active VCCs for the given +interface are displayed. +If an interface and VPI are specified, all active VCCs for the VPI +on the given interface are displayed. +If an interface, VPI, and VCI are specified, only the specified VCC on +the given interface is displayed (note that this could actually be +two VCCs, since SPANS considers SVCs to be unidirectional). +.PP +.SS IP Management Subcommands: +\fIatm add ARP [<netif>] <host> <ATM address>\fP +.PP +where: +.in +10 +.ti -5 +\fI<netif>\fP is the optional name of the network interface the +ATMARP entry is to be associated with. +If no name is specified, a network interface is chosen depending +on the IP address of the host being added. +.ti -5 +\fI<host>\fP is the host name or IP address of the host to +be added to the ATMARP table, +.ti -5 +\fI<ATM address>\fP is the ATM address of the host. +.in -10 +.PP +This command adds an entry to the ATMARP table for ATM. +The given host's IP address is associated with the given ATM address. +When IP needs to transmit data to the host, the specified ATM +address will be used to open an SVC. +.PP +The entry will be marked as permanent in the ATMARP table and will not +be subject to aging. +.PP +.in +5 +.ti -5 +\fIatm add PVC <interface> <vpi> <vci> <aal> <encaps> IP <netif> <host> | dynamic\fP +.in -5 +.PP +where: +.in +10 +.ti -5 +\fI<interface>\fP specifies the physical interface where the PVC +is to terminate, +.ti -5 +\fI<vpi>\fP specifies the Virtual Path Identifier (VPI) of the PVC, +.ti -5 +\fI<vci>\fP specifies the Virtual Channel Identifier (VCI) of the PVC, +.ti -5 +\fI<aal>\fP specifies the ATM Adaptation Layer (AAL) for the PVC. +Valid choices are "null" or "AAL0" for the null AAL; "AAL1" for +AAL 1; "AAL2" for AAL 2; "AAL3", "AAL4", or "AAL3/4" for AAL 3/4; +and "AAL5" for AAL 5, +.ti -5 +\fI<encaps>\fP specifies the encapsulation for the PVC. +Valid choices are "null" or "none" for null encapsulation, and +"LLC/SNAP", "LLC", or "SNAP" for LLC/SNAP encapsulation, +.ti -5 +\fIIP\fP specifies that the owner of the PVC is IP. +.ti -5 +\fI<netif>\fP specifies the network interface which the PVC is +to be associated with. +The network interface must exist and be associated with the +specified physical interface, +.ti -5 +\fI<host> | dynamic\fP gives the address of the host at +the far end of the PVC, or the word "dynamic" if its address +is to be determined with Inverse ARP. +If "dynamic" is specified, LLC/SNAP encapsulation must also +be specified. +.PP +This command creates a PVC with the specified attributes and attaches +it to IP. +.PP +\fIatm delete ARP [<netif>] <host>\fP +.PP +where: +.in +10 +.ti -5 +\fI<netif>\fP is the optional name of the network interface the +ATMARP entry is associated with. +If no name is specified, the specified host is deleted from the +cache regardless of what network interface it is associated with. +.ti -5 +\fI<host>\fP is the host name or IP address of the host to +be deleted from the ATMARP table. +.PP +This command deletes the specified host's entry from the ATMARP table. +.PP +\fIatm set arpserver <netif> <ATM address> | local [<IP prefix> ...]\fP +.PP +where: +.in +10 +.ti -5 +\fI<netif>\fP specifies the network interface for which the +ATMARP server address is to be set. +.ti -5 +\fI<ATM address>\fP specifies the ATM address of the host which is to +provide ATMARP service. +If "local" is specified instead of an ATM address, the host on +which the command is issued will become the ATMARP server. +.ti -5 +\fI<IP prefix> ...\fP is an optional list of IP prefixes +that the ATMARP server will provide information about. +An IP prefix is specified as a dotted decimal IP address, followed by +a slash, followed a number specifying how many bits of the IP address +are significant. +For example, 10.0.0.0/8 indicates that the ATMARP server will provide +services for all addresses on IP network 10. +The IP subnetwork which the network interface belongs to is +automatically included. +.in -10 +.PP +This command sets the address of the ATMARP server for a network +interface. +.PP +.I atm show ARP [<host>] +.PP +displays the following information: +.PP +.B Net Intf +\- the network interface which traffic for the entry will use. +.PP +.B Flags +\- flags showing whether the entry is valid and whether it is +permanent. +\- flags giving further information about the ATMARP entry. +The meanings of the characters in the flags are: +.PP +.in +5 +P - the entry is permanent +.br +R - the entry has been refreshed +.br +V - the entry is valid +.in -5 +.PP +.B Age +\- the number of minutes for which the entry will remain valid. +.PP +.B Origin +\- the source of the ATMARP entry. +Possible values are: +.in +16 +.ti -11 +LOCAL\ ----\ The entry is for an interface on the host. +.ti -11 +PERM\ -----\ The entry is permanent. +This is used for entries that are created with the +\fIadd ARP\fP command. +.ti -11 +REG\ ------\ The entry was created as the result of a host +registering with the ATMARP server. +.ti -11 +SCSP\ -----\ The entry was learned via SCSP. +.ti -11 +LOOKUP\ ---\ The entry was created as the result of a host +performing an ATMARP lookup. +.ti -11 +PEER_RSP\ -\ The entry was created as the result of a host +answering an InARP Request. +.ti -11 +PEER_REQ\ -\ The entry was created as the result of a host +sending an InARP Request. +.in -5 +.PP +.B ATM address +\- the ATM address of the host the entry refers to. +.PP +.B IP address +\- the IP address or domain name of the host the entry refers to. +.PP +If no parameters are specified on the \fIshow ARP\fP subcommand, +the whole ATMARP table will be displayed. +If a host name or IP address is specified, only information about the +given host is displayed. +.PP +This command dislays both information that has been learned dynamically +(through one form or another of ATMARP and via SCSP) and information +which has been configured by the user (through the \fIadd ARP\fP +subcommand). +.PP +.I atm show arpserver [<netif>] +.PP +displays the following information: +.PP +.B Net Intf +\- the network interface for which information is being displayed. +.PP +.B State +\- the state of the connection to the ATMARP server. +Possible values are: +.in +16 +.ti -11 +NOT_CONF\ -\ No ATMARP server has been configured for the interface. +.ti -11 +SERVER\ ---\ The host is the ATMARP server. +.ti -11 +PEND_ADR\ -\ No ATM address has been set for the interface. +.ti -11 +POPEN\ ----\ The host is attempting to open a VCC to the ATMARP server. +.ti -11 +REGISTER\ -\ The host has a VCC open to the ATMARP server and is in +the process of registering with the server. +.ti -11 +ACTIVE\ ---\ The ATMARP server connection is active. +.in -16 +.PP +.B ATM Address +\- the ATM address of the ATMARP server. +.PP +If no parameters are specified on the \fIshow arpserver\fP subcommand, +the ATMARP servers for all network interfaces will be displayed. +If an interface name is specified, only information about the given +network interface is displayed. +.PP +.I atm show IPVCC [<host> | <netif>] +.PP +displays the following information: +.PP +.B Net Intf +\- the name of the network interface at which the VCC terminates. +.PP +.B VPI +\- the Virtual Path Identifier (VPI) for the VCC. +.PP +.B VCI +\- the Virtual Channel Identifier (VCI) for the VCC. +.PP +.B State +\- the state of the VCC. +Possible values are: +.in +15 +.ti -10 +PMAP\ ----\ The host has an IP packet to send and is waiting for +an ATMARP mapping. +.ti -10 +POPEN\ ---\ The VCC is being opened. +.ti -10 +PACCEPT\ -\ A VCC from a remote host is being accepted. +.ti -10 +ACTPENT\ -\ A PVC is open, but no ATMARP information is +available for it yet. +.ti -10 +ACTIVE\ --\ The VCC is active. +.in -15 +.PP +.B Flags +\- flags giving further information about the VCC. +The meanings of the characters in the flags are: +.PP +.in +5 +S - the VCC is an SVC +.br +P - the VCC is a PVC +.br +L - the VCC uses LLC/SNAP encapsulation +.br +M - the IP-to-ATM address mapping for the VCC is valid +.br +N - there is no idle timeout for the VCC +.in -5 +.PP +.B IP Address +\- the name and IP address of the host at the remote end of the VCC. +.PP +If no parameters are specified on the \fIshow IPVCC\fP subcommand, all +active VCCs are displayed. +If a host name is specified, the active VCC(s) for the given +host are displayed. +If a network interface name is specified, the active VCC(s) for the +given network interface are displayed. +.PP +.SS Miscellaneous Subcommands: +.I atm help +.PP +displays a synopsis of the atm command with its subcommands +and their parameters. +.PP +.I atm show version +displays the version of the running HARP software. +.fi +.SH "SEE ALSO" +\fIilmid\fP (8); \fIscspd\fP (8); \fIatmarpd\fP (8). +.fi +.SH BUGS +Care must be taken to avoid confusing physical interfaces and +network interfaces. +.PP +Please report any bugs to harp-bugs@magic.net. +.fi +.SH COPYRIGHT +Copyright (c) 1994-1998, Network Computing Services, Inc. +.fi +.SH AUTHORS +John Cavanaugh, Network Computing Services, Inc. +.br +Mike Spengler, Network Computing Services, Inc. +.br +Joe Thomas, Network Computing Services, Inc. +.fi +.SH ACKNOWLEDGMENTS +This software was developed with the support of the Defense +Advanced Research Projects Agency (DARPA). diff --git a/sbin/atm/atm/atm.c b/sbin/atm/atm/atm.c new file mode 100644 index 0000000..a668b74 --- /dev/null +++ b/sbin/atm/atm/atm.c @@ -0,0 +1,1072 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm.c,v 1.17 1998/08/06 16:57:47 johnc Exp $ + * + */ + +/* + * User configuration and display program + * -------------------------------------- + * + * Main routine + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm.c,v 1.17 1998/08/06 16:57:47 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.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 <libatm.h> +#include "atm.h" + + +/* + * 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\ + 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 + */ + +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, "<intf> <protocol>" }, + { "delete", 0, 0, NULL, (char *) dlt_subcmd }, + { "detach", 1, 1, detach, "<intf>" }, + { "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, "[<netif>] <IP addr> <ATM addr>" }, + { "pvc", 6, 12, pvc_add, "<intf> <vpi> <vci> <aal> <encaps> <owner> ..." }, + { 0, 0, 0, NULL, "" } +}; + +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, "" } +}; + +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, ""} +}; + +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, (char *) stats_subcmd }, + { "vcc", 0, 3, show_vcc, "[<intf>] [<vpi> [<vci>] | SVC | PVC]" }, + { "version", 0, 0, show_version, "" }, + { 0, 0, 0, NULL, "" } +}; + +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 + */ +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] = ""; + + +main(argc, argv) + int argc; + char **argv; +{ + int error; + + /* + * Save program name, ignoring any path components + */ + if (prog = (char *)strrchr(argv[0], '/')) + 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)) + 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 <interface_name> <protocol_name> + * + * 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 <interface_name> + * + * 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 <interface_name> <vpi> <vci> <aal> <encaps> + * <owner_name> + * + * 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 [<netif>] <IP addr> <ATM addr> + * + * 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, rc, 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 <interface_name> <vpi> <vci> + * + * 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 <interface_name> <vpi> <vci> + * + * 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 <IP addr> + * + * 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, ""); +} diff --git a/sbin/atm/atm/atm.h b/sbin/atm/atm/atm.h new file mode 100644 index 0000000..efb8d1e --- /dev/null +++ b/sbin/atm/atm/atm.h @@ -0,0 +1,212 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm.h,v 1.9 1998/07/09 21:23:53 johnc Exp $ + * + */ + +/* + * User configuration and display program + * -------------------------------------- + * + * Control blocks + * + */ + +#define MAX_NIFS 32 /* Max network interfaces */ +#define MIN_VCI 32 /* Smallest non-reserved VCI */ + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + + +/* + * User commands + */ +struct cmd { + char *name; /* Command name */ + int minp; /* Minimum number of parameters */ + int maxp; /* Maximum number of parameters */ + void (*func) /* Processing function */ + __P((int, char **, struct cmd *)); + char *help; /* User help string */ +}; + + +/* + * Supported signalling protocols + */ +struct proto { + char *p_name; /* Protocol name */ + u_char p_id; /* Protocol id */ +}; + + +/* + * Table of state names + */ +struct state { + char *s_name; /* State name */ + u_char s_id; /* State id */ +}; + + +/* + * Supported signalling protocol states + */ +struct proto_state { + char *p_name; /* Signalling manager name */ + struct state *p_state; /* Protocol state table */ + struct state *v_state; /* Protocol VCC state table */ + u_char p_id; /* Protocol ID */ +}; + + +/* + * Supported VCC owners + */ +struct owner { + char *o_name; /* Owner name */ + u_int o_sap; /* Owner's SAP */ + void (*o_pvcadd) /* PVC ADD processing function */ + __P((int, char **, struct cmd *, struct atmaddreq *, + struct air_int_rsp *)); +}; + + +/* + * Supported AALs + */ +struct aal { + char *a_name; /* AAL name */ + u_char a_id; /* AAL code */ +}; + + +/* + * Supported encapsulations + */ +struct encaps { + char *e_name; /* Encapsulation name */ + u_char e_id; /* Encapsulation code */ +}; + + +/* + * External variables + */ +extern char *prog; /* Program invocation */ +extern char prefix[]; /* Current command prefix */ + +/* + * Global function declarations + */ + /* atm.c */ +int do_cmd __P((struct cmd *, int, char **)); +void usage __P((struct cmd *, char *)); +void attach __P((int, char **, struct cmd *)); +void detach __P((int, char **, struct cmd *)); +void pvc_add __P((int, char **, struct cmd *)); +void arp_add __P((int, char **, struct cmd *)); +void pvc_dlt __P((int, char **, struct cmd *)); +void svc_dlt __P((int, char **, struct cmd *)); +void vcc_dlt __P((int, char **, struct cmd *, struct atmdelreq *)); +void arp_dlt __P((int, char **, struct cmd *)); +void help __P((int, char **, struct cmd *)); + + /* atm_eni.c */ +void show_eni_stats __P((char *, int, char **)); +void print_eni_oc3 __P((struct air_vinfo_rsp *)); +void print_eni_atm __P((struct air_vinfo_rsp *)); +void print_eni_aal0 __P((struct air_vinfo_rsp *)); +void print_eni_aal5 __P((struct air_vinfo_rsp *)); +void print_eni_driver __P((struct air_vinfo_rsp *)); + + /* atm_fore200.c */ +void show_fore200_stats __P((char *, int, char **)); +void print_fore200_taxi __P((struct air_vinfo_rsp *)); +void print_fore200_oc3 __P((struct air_vinfo_rsp *)); +void print_fore200_dev __P((struct air_vinfo_rsp *)); +void print_fore200_atm __P((struct air_vinfo_rsp *)); +void print_fore200_aal0 __P((struct air_vinfo_rsp *)); +void print_fore200_aal4 __P((struct air_vinfo_rsp *)); +void print_fore200_aal5 __P((struct air_vinfo_rsp *)); +void print_fore200_driver __P((struct air_vinfo_rsp *)); + + /* atm_inet.c */ +void ip_pvcadd __P((int, char **, struct cmd *, struct atmaddreq *, + struct air_int_rsp *)); + + /* atm_print.c */ +void print_arp_info __P((struct air_arp_rsp *)); +void print_asrv_info __P((struct air_asrv_rsp *)); +void print_intf_info __P((struct air_int_rsp *)); +void print_ip_vcc_info __P((struct air_ip_vcc_rsp *)); +void print_netif_info __P((struct air_netif_rsp *)); +void print_intf_stats __P((struct air_phy_stat_rsp *)); +void print_vcc_stats __P((struct air_vcc_rsp *)); +void print_vcc_info __P((struct air_vcc_rsp *)); +void print_version_info __P((struct air_version_rsp *)); + + /* atm_set.c */ +void set_arpserver __P((int, char **, struct cmd *)); +void set_macaddr __P((int, char **, struct cmd *)); +void set_netif __P((int, char **, struct cmd *)); +void set_prefix __P((int, char **, struct cmd *)); + + /* atm_show.c */ +void show_arp __P((int, char **, struct cmd *)); +void show_arpserv __P((int, char **, struct cmd *)); +void show_config __P((int, char **, struct cmd *)); +void show_intf __P((int, char **, struct cmd *)); +void show_ip_vcc __P((int, char **, struct cmd *)); +void show_netif __P((int, char **, struct cmd *)); +void show_intf_stats __P((int, char **, struct cmd *)); +void show_vcc_stats __P((int, char **, struct cmd *)); +void show_vcc __P((int, char **, struct cmd *)); +void show_version __P((int, char **, struct cmd *)); + + /* atm_subr.c */ +char * get_vendor __P((int)); +char * get_adapter __P((int)); +char * get_media_type __P((int)); +char * get_bus_type __P((int)); +char * get_bus_slot_info __P((int, u_long)); +char * get_adapter_name __P((char *)); +int do_info_ioctl __P((struct atminfreq *, int)); +int get_vcc_info __P((char *, struct air_vcc_rsp **)); +int verify_nif_name __P((char *)); +struct sockaddr_in * + get_ip_addr __P((char *)); +int get_hex_addr __P((char *, u_char *, int)); +char * format_mac_addr __P((Mac_addr *)); +int parse_ip_prefix __P((char *, struct in_addr *)); +int compress_prefix_list __P((struct in_addr *, int)); +void check_netif_name __P((char *)); +void sock_error __P((int)); diff --git a/sbin/atm/atm/atm_eni.c b/sbin/atm/atm/atm_eni.c new file mode 100644 index 0000000..272e48f --- /dev/null +++ b/sbin/atm/atm/atm_eni.c @@ -0,0 +1,437 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_eni.c,v 1.8 1998/08/26 23:29:31 mks Exp $ + * + */ + +/* + * User configuration and display program + * -------------------------------------- + * + * Routines for Efficient-specific subcommands + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_eni.c,v 1.8 1998/08/26 23:29:31 mks Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.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_ioctl.h> + +#include <libatm.h> +#include "atm.h" +#include <dev/hea/eni_stats.h> + + +/* + * Local constants + */ +#define SHOW_PHY 1 +#define SHOW_ATM 2 +#define SHOW_AAL0 4 +#define SHOW_AAL5 8 +#define SHOW_DRIVER 64 + + +/* + * Headers for statistics + */ +#define ATM_STATS_HDR \ +"%s ATM Layer Statistics\n\ + Cells In Cells Out\n" + +#define AAL0_STATS_HDR \ +"%s AAL 0 Statistics\n\ + Cells In Cells Out Cell Drops\n" + +#define AAL5_STATS_HDR \ +"%s AAL 5 Statistics\n\ + CRC/Len CRC Proto PDU\n\ + Cells In Cells Out Errs Drops PDUs In PDUs Out Errs Errs Drops\n" + +#define DRIVER_STATS_HDR_1 \ +"%s Device Driver Statistics\n\ + Buf Buf Buf Buf Can't VCC VCC No No No RX RX\n\ + Req No No Alrdy Find PDU Range Resrc RX DMA Queue\n\ + Size Descr Mem Free Descr Size Error In Bufs Room Full\n" + +#define DRIVER_STATS_HDR_2 \ +"%s Device Driver Statistics\n\ + No ATM No RX No TX Seg Max No No No TX\n\ + RX IntrQ DMA DMA Not Seg Seg TX Resrc DMA\n\ + VCC Full Room Addr Align Pad Out Buf Out Room\n" + +#define OC3_STATS_HDR \ +"%s OC-3c Statistics\n\ +Section Path Line Line Path Corr Uncorr\n\ +BIP8 BIP8 BIP24 FEBE FEBE HCS HCS\n\ +Errs Errs Errs Errs Errs Errs Errs\n" + + +/* + * Process show ENI statistics command + * + * The statistics printed are vendor-specific, depending on the brand of + * the interface card. + * + * Command format: + * atm show stats interface [<interface-name> [phy | dev | atm | + aal0 | aal5 | driver ]] + * + * Arguments: + * intf interface to print statistics for + * argc number of remaining arguments to command + * argv pointer to remaining argument strings + * + * Returns: + * none + * + */ +void +show_eni_stats(intf, argc, argv) + char *intf; + int argc; + char **argv; +{ + int buf_len, stats_type; + struct atminfreq air; + struct air_vinfo_rsp *stats; + + /* + * Get statistics type qualifier + */ + if (!strcasecmp("phy", argv[0])) { + stats_type = SHOW_PHY; + } else if (!strcasecmp("atm", argv[0])) { + stats_type = SHOW_ATM; + } else if (!strcasecmp("aal0", argv[0])) { + stats_type = SHOW_AAL0; + } else if (!strcasecmp("aal5", argv[0])) { + stats_type = SHOW_AAL5; + } else if (!strcasecmp("driver", argv[0])) { + stats_type = SHOW_DRIVER; + } else { + fprintf(stderr, "%s: Illegal or unsupported statistics type\n", prog); + exit(1); + } + argc--; argv++; + + /* + * Get vendor-specific statistics from the kernel + */ + UM_ZERO(&air, sizeof(air)); + air.air_opcode = AIOCS_INF_VST; + strcpy(air.air_vinfo_intf, intf); + buf_len = do_info_ioctl(&air, sizeof(struct air_vinfo_rsp) + 1024); + 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", + intf); + break; + default: + perror("ioctl (AIOCINFO)"); + break; + } + exit(1); + } + stats = (struct air_vinfo_rsp *) air.air_buf_addr; + + /* + * Print the statistics + */ + if (buf_len < sizeof(struct air_vinfo_rsp) + + sizeof(Eni_stats)) { + UM_FREE(stats); + return; + } + + switch (stats_type) { + case SHOW_PHY: + print_eni_oc3(stats); + break; + case SHOW_ATM: + print_eni_atm(stats); + break; + case SHOW_AAL0: + print_eni_aal0(stats); + break; + case SHOW_AAL5: + print_eni_aal5(stats); + break; + case SHOW_DRIVER: + print_eni_driver(stats); + break; + } + + UM_FREE(stats); +} + + +/* + * Print ENI OC-3c statistics + * + * Arguments: + * vi pointer to vendor-specific statistics to print + * + * Returns: + * none + * + */ +void +print_eni_oc3(vi) + struct air_vinfo_rsp *vi; +{ + Eni_stats *stats; + + /* + * Bump stats pointer past header info + */ + stats = (Eni_stats *) + ((u_long) vi + sizeof(struct air_vinfo_rsp)); + + /* + * Print a header + */ + printf(OC3_STATS_HDR, get_adapter_name(vi->avsp_intf)); + + /* + * Print the OC-3c info + */ + printf("%7d %7d %7d %7d %7d %7d %7d\n", + stats->eni_st_oc3.oc3_sect_bip8, + stats->eni_st_oc3.oc3_path_bip8, + stats->eni_st_oc3.oc3_line_bip24, + stats->eni_st_oc3.oc3_line_febe, + stats->eni_st_oc3.oc3_path_febe, + stats->eni_st_oc3.oc3_hec_corr, + stats->eni_st_oc3.oc3_hec_uncorr); +} + + +/* + * Print ENI ATM statistics + * + * Arguments: + * vi pointer to vendor-specific statistics to print + * + * Returns: + * none + * + */ +void +print_eni_atm(vi) + struct air_vinfo_rsp *vi; +{ + Eni_stats *stats; + + /* + * Bump stats pointer past header info + */ + stats = (Eni_stats *) + ((u_long) vi + sizeof(struct air_vinfo_rsp)); + + /* + * Print a header + */ + printf(ATM_STATS_HDR, get_adapter_name(vi->avsp_intf)); + + /* + * Print the ATM layer info + */ + printf("%10d %10d\n", + stats->eni_st_atm.atm_rcvd, + stats->eni_st_atm.atm_xmit); +} + + +/* + * Print ENI AAL 0 statistics + * + * Arguments: + * vi pointer to vendor-specific statistics to print + * + * Returns: + * none + * + */ +void +print_eni_aal0(vi) + struct air_vinfo_rsp *vi; +{ + Eni_stats *stats; + + /* + * Bump stats pointer past header info + */ + stats = (Eni_stats *) + ((u_long) vi + sizeof(struct air_vinfo_rsp)); + + /* + * Print a header + */ + printf(AAL0_STATS_HDR, get_adapter_name(vi->avsp_intf)); + + /* + * Print the AAL 0 info + */ + printf("%10d %10d %10d\n", + stats->eni_st_aal0.aal0_rcvd, + stats->eni_st_aal0.aal0_xmit, + stats->eni_st_aal0.aal0_drops); +} + + +/* + * Print ENI AAL 5 statistics + * + * Arguments: + * vi pointer to vendor-specific statistics to print + * + * Returns: + * none + * + */ +void +print_eni_aal5(vi) + struct air_vinfo_rsp *vi; +{ + Eni_stats *stats; + + /* + * Bump stats pointer past header info + */ + stats = (Eni_stats *) + ((u_long) vi + sizeof(struct air_vinfo_rsp)); + + /* + * Print a header + */ + printf(AAL5_STATS_HDR, get_adapter_name(vi->avsp_intf)); + + /* + * Print the AAL 5 info + */ + printf("%10d %10d %5d %5d %9d %9d %5d %5d %5d\n", + stats->eni_st_aal5.aal5_rcvd, + stats->eni_st_aal5.aal5_xmit, + stats->eni_st_aal5.aal5_crc_len, + stats->eni_st_aal5.aal5_drops, + stats->eni_st_aal5.aal5_pdu_rcvd, + stats->eni_st_aal5.aal5_pdu_xmit, + stats->eni_st_aal5.aal5_pdu_crc, + stats->eni_st_aal5.aal5_pdu_errs, + stats->eni_st_aal5.aal5_pdu_drops); +} + +/* + * Print Efficient device driver statistics + * + * Arguments: + * vi pointer to vendor-specific statistics to print + * + * Returns: + * none + * + */ +void +print_eni_driver(vi) + struct air_vinfo_rsp *vi; +{ + Eni_stats *stats; + + /* + * Bump stats pointer past header info + */ + stats = (Eni_stats *) + ((u_long) vi + sizeof(struct air_vinfo_rsp)); + + /* + * Print 1st header + */ + printf(DRIVER_STATS_HDR_1, get_adapter_name(vi->avsp_intf)); + + /* + * Print the driver info + */ + printf ( "%5d %5d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n", + stats->eni_st_drv.drv_mm_toobig, + stats->eni_st_drv.drv_mm_nodesc, + stats->eni_st_drv.drv_mm_nobuf, + stats->eni_st_drv.drv_mm_notuse, + stats->eni_st_drv.drv_mm_notfnd, + stats->eni_st_drv.drv_vc_maxpdu, + stats->eni_st_drv.drv_vc_badrng, + stats->eni_st_drv.drv_rv_norsc, + stats->eni_st_drv.drv_rv_nobufs, + stats->eni_st_drv.drv_rv_nodma, + stats->eni_st_drv.drv_rv_rxq + ); + + /* + * Print 2nd header + */ + printf(DRIVER_STATS_HDR_2, get_adapter_name(vi->avsp_intf)); + + /* + * Print the driver info + */ + printf ( "%5d %5d %5d %5d %5d %5d %5d %7d %5d %7d\n", + stats->eni_st_drv.drv_rv_novcc, + stats->eni_st_drv.drv_rv_intrq, + stats->eni_st_drv.drv_rv_segdma, + stats->eni_st_drv.drv_xm_segdma, + stats->eni_st_drv.drv_xm_segnoal, + stats->eni_st_drv.drv_xm_seglen, + stats->eni_st_drv.drv_xm_maxpdu, + stats->eni_st_drv.drv_xm_nobuf, + stats->eni_st_drv.drv_xm_norsc, + stats->eni_st_drv.drv_xm_nodma + ); + + +} + diff --git a/sbin/atm/atm/atm_fore200.c b/sbin/atm/atm/atm_fore200.c new file mode 100644 index 0000000..9dd64b4 --- /dev/null +++ b/sbin/atm/atm/atm_fore200.c @@ -0,0 +1,603 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_fore200.c,v 1.10 1998/08/26 23:29:31 mks Exp $ + * + */ + +/* + * User configuration and display program + * -------------------------------------- + * + * Routines for Fore SBA-200-specific subcommands + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_fore200.c,v 1.10 1998/08/26 23:29:31 mks Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.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_ioctl.h> + +#include <libatm.h> +#include "atm.h" +#include <dev/hfa/fore_aali.h> +#include <dev/hfa/fore_slave.h> +#include <dev/hfa/fore_stats.h> + + +/* + * Local constants + */ +#define SHOW_PHY 1 +#define SHOW_DEV 2 +#define SHOW_ATM 4 +#define SHOW_AAL0 8 +#define SHOW_AAL4 16 +#define SHOW_AAL5 32 +#define SHOW_DRIVER 64 + + +/* + * Headers for statistics + */ +#define TAXI_STATS_HDR \ +"%s TAXI Statistics\n\ + CRC Errs Framing Errs\n" + +#define DEV_STATS_HDR \ +"%s Device Statistics\n\ +Type 1 Type 1 Type 2 Type 2\n\ +Small Buff Large Buff Small Buff Large Buff Receive Receive\n\ +Alloc Fail Alloc Fail Alloc Fail Alloc Fail Queue Full Carrier\n" + +#define ATM_STATS_HDR \ +"%s ATM Layer Statistics\n\ + Cells In Cells Out VPI Range VPI NoConn VCI Range VCI NoConn\n" + +#define AAL0_STATS_HDR \ +"%s AAL 0 Statistics\n\ + Cells In Cells Out Cell Drops\n" + +#define AAL4_STATS_HDR \ +"%s AAL 4 Statistics\n\ + CRC Proto Cell PDU PDU\n\ + Cells In Cells Out Errs Errs Drops PDUs In PDUs Out Errs Drops\n" + +#define AAL5_STATS_HDR \ +"%s AAL 5 Statistics\n\ + CRC/Len CRC Proto PDU\n\ + Cells In Cells Out Errs Drops PDUs In PDUs Out Errs Errs Drops\n" + +#define DRIVER_STATS_HDR \ +"%s Device Driver Statistics\n\ + No Xmit Max Seg No No No IQ No Cmd No\n\ + VCC Queue Seg Not Seg DMA VCC No Mbuf Full DMA Queue DMA\n\ + Out Full Size Align Pad Out In Buff In In Sup Full Cmd\n" + +#define OC3_STATS_HDR \ +"%s OC-3c Statistics\n\ +Section Path Line Line Path Corr Uncorr\n\ +BIP8 BIP8 BIP24 FEBE FEBE HCS HCS\n\ +Errs Errs Errs Errs Errs Errs Errs\n" + + +/* + * Process show Fore SBA-200 statistics command + * + * The statistics printed are vendor-specific, depending on the brand of + * the interface card. + * + * Command format: + * atm show stats interface [<interface-name> [phy | dev | atm | + * aal0 | aal4 | aal5 | driver]] + * + * Arguments: + * intf interface statistics are for + * argc number of remaining arguments to command + * argv pointer to remaining argument strings + * + * Returns: + * none + * + */ +void +show_fore200_stats(intf, argc, argv) + char *intf; + int argc; + char **argv; +{ + int buf_len, stats_type; + struct air_cfg_rsp *cfg; + struct air_vinfo_rsp *stats; + struct atminfreq air; + + /* + * Get statistics type qualifier + */ + if (!strcasecmp("phy", argv[0])) { + stats_type = SHOW_PHY; + } else if (!strcasecmp("dev", argv[0])) { + stats_type = SHOW_DEV; + } else if (!strcasecmp("atm", argv[0])) { + stats_type = SHOW_ATM; + } else if (!strcasecmp("aal0", argv[0])) { + stats_type = SHOW_AAL0; + } else if (!strcasecmp("aal4", argv[0])) { + stats_type = SHOW_AAL4; + } else if (!strcasecmp("aal5", argv[0])) { + stats_type = SHOW_AAL5; + } else if (!strcasecmp("driver", argv[0])) { + stats_type = SHOW_DRIVER; + } else { + fprintf(stderr, "%s: Illegal statistics type\n", prog); + exit(1); + } + argc--; argv++; + + /* + * Get adapter configuration from the kernel + */ + UM_ZERO(&air, sizeof(air)); + air.air_opcode = AIOCS_INF_CFG; + strcpy(air.air_cfg_intf, intf); + buf_len = do_info_ioctl(&air, sizeof(struct air_cfg_rsp)); + 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", + intf); + break; + default: + perror("ioctl (AIOCINFO)"); + break; + } + exit(1); + } + cfg = (struct air_cfg_rsp *) air.air_buf_addr; + + /* + * Get vendor-specific statistics from the kernel + */ + UM_ZERO(&air, sizeof(air)); + air.air_opcode = AIOCS_INF_VST; + strcpy(air.air_vinfo_intf, intf); + buf_len = do_info_ioctl(&air, sizeof(struct air_vinfo_rsp) + 1024); + 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", + intf); + break; + default: + perror("ioctl (AIOCINFO)"); + break; + } + exit(1); + } + stats = (struct air_vinfo_rsp *) air.air_buf_addr; + + /* + * Print the statistics + */ + if (buf_len < sizeof(struct air_vinfo_rsp) + + sizeof(Fore_stats)) { + UM_FREE(stats); + UM_FREE(cfg); + return; + } + + switch (stats_type) { + case SHOW_PHY: + switch (cfg->acp_media) { + case MEDIA_TAXI_100: + case MEDIA_TAXI_140: + print_fore200_taxi(stats); + break; + case MEDIA_OC3C: + print_fore200_oc3(stats); + break; + case MEDIA_OC12C: + break; + default: + break; + } + break; + case SHOW_DEV: + print_fore200_dev(stats); + break; + case SHOW_ATM: + print_fore200_atm(stats); + break; + case SHOW_AAL0: + print_fore200_aal0(stats); + break; + case SHOW_AAL4: + print_fore200_aal4(stats); + break; + case SHOW_AAL5: + print_fore200_aal5(stats); + break; + case SHOW_DRIVER: + print_fore200_driver(stats); + break; + } + + UM_FREE(stats); + UM_FREE(cfg); +} + + +/* + * Print Fore ASX-200 TAXI statistics + * + * Arguments: + * vi pointer to vendor-specific statistics to print + * + * Returns: + * none + * + */ +void +print_fore200_taxi(vi) + struct air_vinfo_rsp *vi; +{ + Fore_stats *stats; + + /* + * Bump stats pointer past header info + */ + stats = (Fore_stats *) + ((u_long) vi + sizeof(struct air_vinfo_rsp)); + + /* + * Print a header + */ + printf(TAXI_STATS_HDR, get_adapter_name(vi->avsp_intf)); + + /* + * Print the physical layer info + */ + printf("%10d %12d\n", + stats->st_taxi.taxi_bad_crc, + stats->st_taxi.taxi_framing); +} + + +/* + * Print Fore ASX-200 OC-3c statistics + * + * Arguments: + * vi pointer to vendor-specific statistics to print + * + * Returns: + * none + * + */ +void +print_fore200_oc3(vi) + struct air_vinfo_rsp *vi; +{ + Fore_stats *stats; + + /* + * Bump stats pointer past header info + */ + stats = (Fore_stats *) + ((u_long) vi + sizeof(struct air_vinfo_rsp)); + + /* + * Print a header + */ + printf(OC3_STATS_HDR, get_adapter_name(vi->avsp_intf)); + + /* + * Print the OC-3c info + */ + printf("%7d %7d %7d %7d %7d %7d %7d\n", + stats->st_oc3.oc3_sect_bip8, + stats->st_oc3.oc3_path_bip8, + stats->st_oc3.oc3_line_bip24, + stats->st_oc3.oc3_line_febe, + stats->st_oc3.oc3_path_febe, + stats->st_oc3.oc3_hec_corr, + stats->st_oc3.oc3_hec_uncorr); +} + + +/* + * Print Fore ASX-200 device statistics + * + * Arguments: + * vi pointer to vendor-specific statistics to print + * + * Returns: + * none + * + */ +void +print_fore200_dev(vi) + struct air_vinfo_rsp *vi; +{ + Fore_stats *stats; + + /* + * Bump stats pointer past header info + */ + stats = (Fore_stats *) + ((u_long) vi + sizeof(struct air_vinfo_rsp)); + + /* + * Print a header + */ + printf(DEV_STATS_HDR, get_adapter_name(vi->avsp_intf)); + + /* + * Print the device info + */ + printf("%10d %10d %10d %10d %10d %s\n", + stats->st_misc.buf1_sm_fail, + stats->st_misc.buf1_lg_fail, + stats->st_misc.buf2_sm_fail, + stats->st_misc.buf2_lg_fail, + stats->st_misc.rcvd_pdu_fail, + (stats->st_misc.carrier_status ? "On" : "Off")); +} + + +/* + * Print Fore ASX-200 ATM statistics + * + * Arguments: + * vi pointer to vendor-specific statistics to print + * + * Returns: + * none + * + */ +void +print_fore200_atm(vi) + struct air_vinfo_rsp *vi; +{ + Fore_stats *stats; + + /* + * Bump stats pointer past header info + */ + stats = (Fore_stats *) + ((u_long) vi + sizeof(struct air_vinfo_rsp)); + + /* + * Print a header + */ + printf(ATM_STATS_HDR, get_adapter_name(vi->avsp_intf)); + + /* + * Print the ATM layer info + */ + printf("%10d %10d %10d %10d %10d %10d\n", + stats->st_atm.atm_rcvd, + stats->st_atm.atm_xmit, + stats->st_atm.atm_vpi_range, + stats->st_atm.atm_vpi_noconn, + stats->st_atm.atm_vci_range, + stats->st_atm.atm_vci_noconn); +} + + +/* + * Print Fore ASX-200 AAL 0 statistics + * + * Arguments: + * vi pointer to vendor-specific statistics to print + * + * Returns: + * none + * + */ +void +print_fore200_aal0(vi) + struct air_vinfo_rsp *vi; +{ + Fore_stats *stats; + + /* + * Bump stats pointer past header info + */ + stats = (Fore_stats *) + ((u_long) vi + sizeof(struct air_vinfo_rsp)); + + /* + * Print a header + */ + printf(AAL0_STATS_HDR, get_adapter_name(vi->avsp_intf)); + + /* + * Print the AAL 0 info + */ + printf("%10d %10d %10d\n", + stats->st_aal0.aal0_rcvd, + stats->st_aal0.aal0_xmit, + stats->st_aal0.aal0_drops); +} + + +/* + * Print Fore ASX-200 AAL 4 statistics + * + * Arguments: + * vi pointer to vendor-specific statistics to print + * + * Returns: + * none + * + */ +void +print_fore200_aal4(vi) + struct air_vinfo_rsp *vi; +{ + Fore_stats *stats; + + /* + * Bump stats pointer past header info + */ + stats = (Fore_stats *) + ((u_long) vi + sizeof(struct air_vinfo_rsp)); + + /* + * Print a header + */ + printf(AAL4_STATS_HDR, get_adapter_name(vi->avsp_intf)); + + /* + * Print the AAL 4 info + */ + printf("%10d %10d %5d %5d %5d %9d %9d %5d %5d\n", + stats->st_aal4.aal4_rcvd, + stats->st_aal4.aal4_xmit, + stats->st_aal4.aal4_crc, + stats->st_aal4.aal4_sar_cs, + stats->st_aal4.aal4_drops, + stats->st_aal4.aal4_pdu_rcvd, + stats->st_aal4.aal4_pdu_xmit, + stats->st_aal4.aal4_pdu_errs, + stats->st_aal4.aal4_pdu_drops); +} + + +/* + * Print Fore ASX-200 AAL 5 statistics + * + * Arguments: + * vi pointer to vendor-specific statistics to print + * + * Returns: + * none + * + */ +void +print_fore200_aal5(vi) + struct air_vinfo_rsp *vi; +{ + Fore_stats *stats; + + /* + * Bump stats pointer past header info + */ + stats = (Fore_stats *) + ((u_long) vi + sizeof(struct air_vinfo_rsp)); + + /* + * Print a header + */ + printf(AAL5_STATS_HDR, get_adapter_name(vi->avsp_intf)); + + /* + * Print the AAL 5 info + */ + printf("%10d %10d %5d %5d %9d %9d %5d %5d %5d\n", + stats->st_aal5.aal5_rcvd, + stats->st_aal5.aal5_xmit, + stats->st_aal5.aal5_crc_len, + stats->st_aal5.aal5_drops, + stats->st_aal5.aal5_pdu_rcvd, + stats->st_aal5.aal5_pdu_xmit, + stats->st_aal5.aal5_pdu_crc, + stats->st_aal5.aal5_pdu_errs, + stats->st_aal5.aal5_pdu_drops); +} + + +/* + * Print Fore ASX-200 device driver statistics + * + * Arguments: + * vi pointer to vendor-specific statistics to print + * + * Returns: + * none + * + */ +void +print_fore200_driver(vi) + struct air_vinfo_rsp *vi; +{ + Fore_stats *stats; + + /* + * Bump stats pointer past header info + */ + stats = (Fore_stats *) + ((u_long) vi + sizeof(struct air_vinfo_rsp)); + + /* + * Print a header + */ + printf(DRIVER_STATS_HDR, get_adapter_name(vi->avsp_intf)); + + /* + * Print the driver info + */ + printf("%4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d %4d\n", + stats->st_drv.drv_xm_notact, + stats->st_drv.drv_xm_full, + stats->st_drv.drv_xm_maxpdu, + stats->st_drv.drv_xm_segnoal, + stats->st_drv.drv_xm_seglen, + stats->st_drv.drv_xm_segdma, + stats->st_drv.drv_rv_novcc, + stats->st_drv.drv_rv_nosbf, + stats->st_drv.drv_rv_nomb, + stats->st_drv.drv_rv_ifull, + stats->st_drv.drv_bf_segdma, + stats->st_drv.drv_cm_full, + stats->st_drv.drv_cm_nodma); + +} diff --git a/sbin/atm/atm/atm_inet.c b/sbin/atm/atm/atm_inet.c new file mode 100644 index 0000000..91b62dc --- /dev/null +++ b/sbin/atm/atm/atm_inet.c @@ -0,0 +1,164 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_inet.c,v 1.9 1998/08/26 23:29:31 mks Exp $ + * + */ + +/* + * User configuration and display program + * -------------------------------------- + * + * IP support + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_inet.c,v 1.9 1998/08/26 23:29:31 mks Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/socket.h> +#include <string.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_ioctl.h> + +#include <libatm.h> +#include "atm.h" + + +/* + * Process add command for a TCP/IP PVC + * + * Command format: + * atm add pvc <intf> <vpi> <vci> <aal> <encaps> IP <netif> + * <IP addr> | dynamic + * + * Arguments: + * argc number of remaining arguments to command + * argv pointer to remaining argument strings + * cmdp pointer to command description + * app pointer to AIOCAPVC structure + * intp pointer to air_int_rsp structure with information + * about the physical interface that is the PVC is for. + * + * Returns: + * none + * + */ +void +ip_pvcadd(argc, argv, cmdp, app, intp) + int argc; + char **argv; + struct cmd *cmdp; + struct atmaddreq *app; + struct air_int_rsp *intp; +{ + char *cp; + char nhelp[128]; + int i, netif_pref_len, netif_no; + + /* + * Yet more validation + */ + if (argc != 2) { + strcpy(nhelp, cmdp->help); + cp = strstr(nhelp, "<netif>"); + if (cp) + strcpy(cp, "ip {dyn|<dst>}"); + fprintf(stderr, "%s: Invalid number of arguments:\n", + prog); + fprintf(stderr, "\tformat is: %s%s %s\n", + prefix, cmdp->name, nhelp); + exit(1); + } + + /* + * Validate and set network interface + */ + UM_ZERO(app->aar_pvc_intf, sizeof(app->aar_pvc_intf)); + netif_pref_len = strlen(intp->anp_nif_pref); + cp = &argv[0][netif_pref_len]; + netif_no = atoi(cp); + for (i=0; i<strlen(cp); i++) { + if (cp[i] < '0' || cp[i] > '9') { + netif_no = -1; + break; + } + } + if ((strlen(argv[0]) > sizeof(app->aar_pvc_intf) - 1) || + (netif_no < 0)) { + fprintf(stderr, "%s: Illegal network interface name\n", + prog); + exit(1); + } + if (strncasecmp(intp->anp_nif_pref, argv[0], netif_pref_len) || + strlen (argv[0]) <= netif_pref_len || + netif_no > intp->anp_nif_cnt - 1) { + fprintf(stderr, "%s: network interface %s is not associated with interface %s\n", + prog, + argv[0], + intp->anp_intf); + exit(1); + } + strcpy(app->aar_pvc_intf, argv[0]); + argc--; argv++; + + /* + * Set PVC destination address + */ + UM_ZERO(&app->aar_pvc_dst, sizeof(struct sockaddr)); + if (strcasecmp(argv[0], "dynamic") == 0 || + strcasecmp(argv[0], "dyn") == 0) { + + /* + * Destination is dynamically determined + */ + app->aar_pvc_flags |= PVC_DYN; + } else { + + /* + * Get destination IP address + */ + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *) &app->aar_pvc_dst; + sin->sin_addr.s_addr = + get_ip_addr(argv[0])->sin_addr.s_addr; + } + argc--; argv++; +} + diff --git a/sbin/atm/atm/atm_print.c b/sbin/atm/atm/atm_print.c new file mode 100644 index 0000000..93aaef8 --- /dev/null +++ b/sbin/atm/atm/atm_print.c @@ -0,0 +1,904 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_print.c,v 1.12 1998/07/30 22:38:56 mks Exp $ + * + */ + +/* + * User configuration and display program + * -------------------------------------- + * + * Print routines for "show" subcommand + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_print.c,v 1.12 1998/07/30 22:38:56 mks Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.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_sigmgr.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_vc.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/sigpvc/sigpvc_var.h> +#include <netatm/spans/spans_var.h> +#include <netatm/uni/uniip_var.h> +#include <netatm/uni/unisig_var.h> +#include "atm.h" + + + +#define ARP_HDR \ +"Net Intf Flags Age Origin\n" + +#define ASRV_HDR \ +"Net Intf State ATM Address\n" + +#define CFG_HDR \ +"Intf Vendor Model Media Bus Serial No\n" + +#define IP_VCC_HDR \ +"Net Intf VPI VCI State Flags IP Address\n" + +#define INTF_HDR \ +"Interface Sigmgr State\n" + +#define NETIF_HDR \ +"Net Intf Phy Intf IP Address\n" + +#define VCC_HDR \ +"Interface VPI VCI AAL Type Dir State Encaps Owner\n" + +#define VCC_STATS_HDR \ +" Input Input Input Output Output Output\n\ +Interface VPI VCI PDUs Bytes Errs PDUs Bytes Errs\n" + +#define VERSION_HDR \ +"Version\n" + +#define PHY_STATS_HDR \ +" Input Input Input Output Output Output Cmd\n\ +Interface PDUs Bytes Errs PDUs Bytes Errs Errs\n" + +/* + * External references + */ +extern struct proto protos[]; +extern struct aal aals[]; +extern struct encaps encaps[]; + +/* + * Local variables + */ +static int arp_hdr = 0; +static int asrv_hdr = 0; +static int cfg_hdr = 0; +static int ip_vcc_hdr = 0; +static int netif_hdr = 0; +static int vcc_hdr = 0; +static int vcc_stats_hdr = 0; +static int phy_stats_hdr = 0; +static int version_hdr = 0; + +/* + * SIGPVC state definitions + */ +struct state sigpvc_states[] = { + { "ACTIVE", SIGPVC_ACTIVE }, + { "DETACH", SIGPVC_DETACH }, + { 0, 0 } +}; + +/* + * SPANS state definitions + */ +struct state spans_states[] = { + { "ACTIVE", SPANS_ACTIVE }, + { "DETACH", SPANS_DETACH }, + { "INIT", SPANS_INIT }, + { "PROBE", SPANS_PROBE }, + { 0, 0 } +}; + +/* + * UNISIG state definitions + */ +struct state unisig_states[] = { + { "NULL", UNISIG_NULL }, + { "ADR_WAIT", UNISIG_ADDR_WAIT }, + { "INIT", UNISIG_INIT }, + { "ACTIVE", UNISIG_ACTIVE }, + { "DETACH", UNISIG_DETACH }, + { 0, 0 } +}; + +/* + * SIGPVC VCC state definitions + */ +struct state sigpvc_vcc_states[] = { + { "NULL", VCCS_NULL }, + { "ACTIVE", VCCS_ACTIVE }, + { "FREE", VCCS_FREE }, + { 0, 0 } +}; + +/* + * SPANS VCC state definitions + */ +struct state spans_vcc_states[] = { + { "NULL", SPANS_VC_NULL }, + { "ACTIVE", SPANS_VC_ACTIVE }, + { "ACT_DOWN", SPANS_VC_ACT_DOWN }, + { "POPEN", SPANS_VC_POPEN }, + { "R_POPEN", SPANS_VC_R_POPEN }, + { "OPEN", SPANS_VC_OPEN }, + { "CLOSE", SPANS_VC_CLOSE }, + { "ABORT", SPANS_VC_ABORT }, + { "FREE", SPANS_VC_FREE }, + {0, 0 } +}; + +/* + * UNISIG VCC state definitions + */ +struct state unisig_vcc_states[] = { + { "NULL", UNI_NULL }, + { "C_INIT", UNI_CALL_INITIATED }, + { "C_OUT_PR", UNI_CALL_OUT_PROC }, + { "C_DELIV", UNI_CALL_DELIVERED }, + { "C_PRES", UNI_CALL_PRESENT }, + { "C_REC", UNI_CALL_RECEIVED }, + { "CONN_REQ", UNI_CONNECT_REQUEST }, + { "C_IN_PR", UNI_CALL_IN_PROC }, + { "ACTIVE", UNI_ACTIVE }, + { "REL_REQ", UNI_RELEASE_REQUEST }, + { "REL_IND", UNI_RELEASE_IND }, + { "SSCF_REC", UNI_SSCF_RECOV }, + { "FREE", UNI_FREE }, + { "ACTIVE", UNI_PVC_ACTIVE }, + { "ACT_DOWN", UNI_PVC_ACT_DOWN }, + {0, 0 } +}; + +/* + * IP VCC state definitions + */ +struct state ip_vcc_states[] = { + { "FREE", IPVCC_FREE }, + { "PMAP", IPVCC_PMAP }, + { "POPEN", IPVCC_POPEN }, + { "PACCEPT", IPVCC_PACCEPT }, + { "ACTPENT", IPVCC_ACTPENT }, + { "ACTIVE", IPVCC_ACTIVE }, + { "CLOSED", IPVCC_CLOSED }, + { 0, 0 } +}; + +/* + * ARP server state definitions + */ +struct state arpserver_states[] = { + { "NOT_CONF", UIAS_NOTCONF }, + { "SERVER", UIAS_SERVER_ACTIVE }, + { "PEND_ADR", UIAS_CLIENT_PADDR }, + { "POPEN", UIAS_CLIENT_POPEN }, + { "REGISTER", UIAS_CLIENT_REGISTER }, + { "ACTIVE", UIAS_CLIENT_ACTIVE }, + { 0, 0 } +}; + +/* + * Supported signalling managers + */ +struct proto_state proto_states[] = { + { "SIGPVC", sigpvc_states, sigpvc_vcc_states, ATM_SIG_PVC }, + { "SPANS", spans_states, spans_vcc_states, ATM_SIG_SPANS }, + { "UNI 3.0", unisig_states, unisig_vcc_states, ATM_SIG_UNI30 }, + { "UNI 3.1", unisig_states, unisig_vcc_states, ATM_SIG_UNI31 }, + { "UNI 4.0", unisig_states, unisig_vcc_states, ATM_SIG_UNI40 }, + { 0, 0, 0, 0 } +}; + +/* + * ATMARP origin values + */ +struct state arp_origins[] = { + { "LOCAL", UAO_LOCAL }, + { "PERM", UAO_PERM }, + { "REG", UAO_REGISTER }, + { "SCSP", UAO_SCSP }, + { "LOOKUP", UAO_LOOKUP }, + { "PEER_RSP", UAO_PEER_RSP }, + { "PEER_REQ", UAO_PEER_REQ }, + { 0, 0 } +}; + + +/* + * Print ARP table information + * + * Arguments: + * ai pointer to a struct air_arp_rsp + * + * Returns: + * none + * + */ +void +print_arp_info(ai) + struct air_arp_rsp *ai; +{ + int i; + char *atm_addr, *ip_addr, *origin; + char age[8], flags[32]; + struct sockaddr_in *sin; + + /* + * Print a header if it hasn't been done yet. + */ + if (!arp_hdr) { + printf(ARP_HDR); + arp_hdr = 1; + } + + /* + * Format the addresses + */ + atm_addr = format_atm_addr(&ai->aap_addr); + sin = (struct sockaddr_in *)&ai->aap_arp_addr; + ip_addr = format_ip_addr(&sin->sin_addr); + + /* + * Decode the flags + */ + UM_ZERO(flags, sizeof(flags)); + if (ai->aap_flags & ARPF_VALID) { + strcat(flags, "V"); + } + if (ai->aap_flags & ARPF_REFRESH) { + strcat(flags, "R"); + } + + /* + * Format the origin + */ + for (i=0; arp_origins[i].s_name != NULL && + ai->aap_origin != arp_origins[i].s_id; + i++); + if (arp_origins[i].s_name) { + origin = arp_origins[i].s_name; + } else { + origin = "-"; + } + + /* + * Format the age + */ + UM_ZERO(age, sizeof(age)); + if (!(ai->aap_flags & ARPF_VALID)) { + strcpy(age, "-"); + } else { + sprintf(age, "%d", ai->aap_age); + } + + /* + * Print the ARP information + */ + printf("%-8s %-5s %3s %s\n ATM address = %s\n IP address = %s\n", + ai->aap_intf, + flags, + age, + origin, + atm_addr, + ip_addr); +} + + +/* + * Print ARP server information + * + * Arguments: + * si pointer to a struct air_asrv_rsp + * + * Returns: + * none + * + */ +void +print_asrv_info(si) + struct air_asrv_rsp *si; +{ + int i; + char *atm_addr, *state; + char print_lis[32]; + struct in_addr *addr; + + /* + * Print a header if it hasn't been done yet. + */ + if (!asrv_hdr) { + printf(ASRV_HDR); + asrv_hdr = 1; + } + + /* + * Format the ATM address of the ARP server + */ + atm_addr = format_atm_addr(&si->asp_addr); + + /* + * Format the server state + */ + for (i=0; arpserver_states[i].s_name != NULL && + si->asp_state != arpserver_states[i].s_id; + i++); + if (arpserver_states[i].s_name) { + state = arpserver_states[i].s_name; + } else { + state = "-"; + } + + /* + * Print the ARP server information + */ + printf("%-8s %-8s %s\n", + si->asp_intf, + state, + atm_addr); + + /* + * Format and print the LIS prefixes + */ + if (si->asp_nprefix) { + addr = (struct in_addr *)((u_long)si + + sizeof(struct air_asrv_rsp)); + printf(" LIS = "); + for (i = 0; i < si->asp_nprefix; i++) { + printf("%s", inet_ntoa(*addr)); + addr++; + printf("/0x%0x", ntohl(addr->s_addr)); + addr++; + if (i < si->asp_nprefix -1) + printf(", "); + } + printf("\n"); + } +} + + +/* + * Print adapter configuration information + * + * Arguments: + * si pointer to a struct air_cfg_rsp + * + * Returns: + * none + * + */ +void +print_cfg_info(si) + struct air_cfg_rsp *si; +{ + char *adapter, *bus, *media, *vendor; + + /* + * Print a header if it hasn't been done yet. + */ + if (!cfg_hdr) { + printf(CFG_HDR); + cfg_hdr = 1; + } + + /* + * Format the vendor name and adapter type + */ + vendor = get_vendor(si->acp_vendor); + adapter = get_adapter(si->acp_device); + + /* + * Format the communications medium + */ + media = get_media_type(si->acp_media); + bus = get_bus_type(si->acp_bustype); + + /* + * Print the ARP server information + */ + printf("%-8s %-8s %-8s %-14s %-4s %d\n", + si->acp_intf, + vendor, + adapter, + media, + bus, + si->acp_serial); + printf(" MAC address = %s\n", + format_mac_addr(&si->acp_macaddr)); + printf(" Hardware version = %s\n", si->acp_hard_vers); + printf(" Firmware version = %s\n", si->acp_firm_vers); +} + + +/* + * Print interface information + * + * Arguments: + * ni pointer to a struct air_int_rsp + * + * Returns: + * none + * + */ +void +print_intf_info(ni) + struct air_int_rsp *ni; +{ + int i; + char nif_names[(IFNAMSIZ *2)+4]; + char *atm_addr, *ip_addr; + char *sigmgr = "-", *state_name = "-"; + struct sockaddr_in *sin; + struct state *s_t; + + /* + * Print a header + */ + printf(INTF_HDR); + + /* + * Translate signalling manager name + */ + for (i=0; proto_states[i].p_state != NULL; i++) + if (ni->anp_sig_proto == proto_states[i].p_id) + break; + if (proto_states[i].p_state != NULL) + sigmgr = proto_states[i].p_name; + + /* + * Get the signalling manager state + */ + if (proto_states[i].p_state != NULL) { + s_t = proto_states[i].p_state; + for (i=0; s_t[i].s_name != NULL; i++) + if (ni->anp_sig_state == s_t[i].s_id) + break; + if (s_t[i].s_name != NULL) + state_name = s_t[i].s_name; + } + + /* + * Format the ATM address + */ + atm_addr = format_atm_addr(&ni->anp_addr); + + /* + * Get the range of NIFs on the physical interface + */ + UM_ZERO(nif_names, sizeof(nif_names)); + if (strlen(ni->anp_nif_pref) == 0) { + strcpy(nif_names, "-"); + } else { + strcpy(nif_names, ni->anp_nif_pref); + strcat(nif_names, "0"); + if (ni->anp_nif_cnt > 1) { + strcat(nif_names, " - "); + strcat(nif_names, ni->anp_nif_pref); + sprintf(&nif_names[strlen(nif_names)], "%d", + ni->anp_nif_cnt-1); + } + } + + + /* + * Print the interface information + */ + printf("%-9s %-7s %s\n", + ni->anp_intf, + sigmgr, + state_name); + printf(" ATM address = %s\n", atm_addr); + printf(" Network interfaces: %s\n", nif_names); +} + + +/* + * Print IP address map information + * + * Arguments: + * ai pointer to a struct air_arp_rsp + * + * Returns: + * none + * + */ +void +print_ip_vcc_info(ai) + struct air_ip_vcc_rsp *ai; +{ + int i; + char *ip_addr, *state; + char flags[32], vpi_vci[16]; + struct sockaddr_in *sin; + + /* + * Print a header if it hasn't been done yet. + */ + if (!ip_vcc_hdr) { + printf(IP_VCC_HDR); + ip_vcc_hdr = 1; + } + + /* + * Format the IP address + */ + sin = (struct sockaddr_in *)&ai->aip_dst_addr; + ip_addr = format_ip_addr(&sin->sin_addr); + + /* + * Format the VPI/VCI + */ + if (ai->aip_vpi == 0 && ai->aip_vci == 0) { + strcpy(vpi_vci, " - -"); + } else { + sprintf(vpi_vci, "%3d %5d", ai->aip_vpi, ai->aip_vci); + } + + /* + * Decode VCC flags + */ + UM_ZERO(flags, sizeof(flags)); + if (ai->aip_flags & IVF_PVC) { + strcat(flags, "P"); + } + if (ai->aip_flags & IVF_SVC) { + strcat(flags, "S"); + } + if (ai->aip_flags & IVF_LLC) { + strcat(flags, "L"); + } + if (ai->aip_flags & IVF_MAPOK) { + strcat(flags, "M"); + } + if (ai->aip_flags & IVF_NOIDLE) { + strcat(flags, "N"); + } + + /* + * Get the state of the VCC + */ + for (i=0; ip_vcc_states[i].s_name != NULL && + ai->aip_state != ip_vcc_states[i].s_id; + i++); + if (ip_vcc_states[i].s_name) { + state = ip_vcc_states[i].s_name; + } else { + state = "-"; + } + + /* + * Print the IP VCC information + */ + printf("%-8s %9s %-7s %-5s %s\n", + ai->aip_intf, + vpi_vci, + state, + flags, + ip_addr); +} + + +/* + * Print network interface information + * + * Arguments: + * ni pointer to a struct air_int_rsp + * + * Returns: + * none + * + */ +void +print_netif_info(ni) + struct air_netif_rsp *ni; +{ + char *ip_addr; + struct sockaddr_in *sin; + + /* + * Print a header + */ + if (!netif_hdr) { + netif_hdr++; + printf(NETIF_HDR); + } + + /* + * Format the protocol address + */ + sin = (struct sockaddr_in *)&ni->anp_proto_addr; + ip_addr = format_ip_addr(&sin->sin_addr); + + /* + * Print the network interface information + */ + printf("%-8s %-8s %s\n", + ni->anp_intf, + ni->anp_phy_intf, + ip_addr); +} + + +/* + * Print physical interface statistics + * + * Arguments: + * pi pointer to a struct air_phy_stat_rsp + * + * Returns: + * none + * + */ +void +print_intf_stats(pi) + struct air_phy_stat_rsp *pi; +{ + int i; + + /* + * Print a header if it hasn't already been done + */ + if (!phy_stats_hdr) { + printf(PHY_STATS_HDR); + phy_stats_hdr = 1; + } + + /* + * Print the interface statistics + */ + printf("%-9s %7d %8d %5d %7d %8d %5d %5d\n", + pi->app_intf, + pi->app_ipdus, + pi->app_ibytes, + pi->app_ierrors, + pi->app_opdus, + pi->app_obytes, + pi->app_oerrors, + pi->app_cmderrors); +} + + +/* + * Print VCC statistics + * + * Arguments: + * vi pointer to VCC statistics to print + * + * Returns: + * none + * + */ +void +print_vcc_stats(vi) + struct air_vcc_rsp *vi; +{ + + /* + * Print a header if it hasn't already been done + */ + if (!vcc_stats_hdr) { + printf(VCC_STATS_HDR); + vcc_stats_hdr = 1; + } + + /* + * Print the VCC statistics + */ + printf("%-9s %3d %4d", + vi->avp_intf, + vi->avp_vpi, + vi->avp_vci); + if ( vi->avp_type & VCC_IN ) + printf ( " %7d %8d %5d", + vi->avp_ipdus, + vi->avp_ibytes, + vi->avp_ierrors); + else + printf ( " - - -" ); + + if ( vi->avp_type & VCC_OUT ) + printf ( " %7d %8d %5d\n", + vi->avp_opdus, + vi->avp_obytes, + vi->avp_oerrors); + else + printf ( " - - -\n" ); +} + + +/* + * Print VCC information + * + * Arguments: + * vi pointer to a struct air_vcc_rsp + * + * Returns: + * none + * + */ +void +print_vcc_info(vi) + struct air_vcc_rsp *vi; +{ + int i; + char *aal_name = "-" , *encaps_name = "-", *owner_name = "-"; + char *proto_name = "-", *state_name = "-", *type_name = "-"; + char dir_name[10]; + struct state *s_t; + + /* + * Print a header if it hasn't already been done + */ + if (!vcc_hdr) { + printf(VCC_HDR); + vcc_hdr = 1; + } + + /* + * Translate AAL + */ + for (i=0; aals[i].a_name != NULL; i++) + if (vi->avp_aal == aals[i].a_id) + break; + if (aals[i].a_name) + aal_name = aals[i].a_name; + + /* + * Translate VCC type + */ + if (vi->avp_type & VCC_PVC) + type_name = "PVC"; + else if (vi->avp_type & VCC_SVC) + type_name = "SVC"; + /* + * Translate VCC direction + */ + UM_ZERO(dir_name, sizeof(dir_name)); + if (vi->avp_type & VCC_IN) + strcat(dir_name, "In"); + if (vi->avp_type & VCC_OUT) + strcat(dir_name, "Out"); + if (strlen(dir_name) == 0) + strcpy(dir_name, "-"); + + /* + * Translate state + */ + for (i=0; proto_states[i].p_state != NULL; i++) + if (vi->avp_sig_proto == proto_states[i].p_id) + break; + if (proto_states[i].p_state) { + s_t = proto_states[i].v_state; + for (i=0; s_t[i].s_name != NULL; i++) + if (vi->avp_state == s_t[i].s_id) + break; + if (s_t[i].s_name) + state_name = s_t[i].s_name; + } + + /* + * Translate encapsulation + */ + for (i=0; encaps[i].e_name != NULL; i++) + if (vi->avp_encaps == encaps[i].e_id) + break; + if (encaps[i].e_name) + encaps_name = encaps[i].e_name; + + /* + * Print the VCC information + */ + printf("%-9s %3d %5d %-4s %-4s %-5s %-8s %-8s ", + vi->avp_intf, + vi->avp_vpi, + vi->avp_vci, + aal_name, + type_name, + dir_name, + state_name, + encaps_name); + + /* + * Print VCC owners' names + */ + for (i = 0, owner_name = vi->avp_owners; + i < O_CNT - 1 && strlen(owner_name); + i++, owner_name += (T_ATM_APP_NAME_LEN + 1)) { + if (i > 0) + printf(", "); + printf("%s", owner_name); + } + if (i == 0) + printf("-"); + printf("\n"); + + /* + * Print destination address if it's an SVC + */ + if (vi->avp_type & VCC_SVC) { + printf(" Dest = %s\n", + format_atm_addr(&vi->avp_daddr)); + } +} + + +/* + * Print network interface information + * + * Arguments: + * ni pointer to a struct air_int_rsp + * + * Returns: + * none + * + */ +void +print_version_info(vi) + struct air_version_rsp *vi; +{ + char version_str[80]; + + /* + * Print a header + */ + if (!version_hdr) { + version_hdr++; + printf(VERSION_HDR); + } + + /* + * Print the interface information + */ + sprintf(version_str, "%d.%d", + ATM_VERS_MAJ(vi->avp_version), + ATM_VERS_MIN(vi->avp_version)); + printf("%7s\n", version_str); +} diff --git a/sbin/atm/atm/atm_set.c b/sbin/atm/atm/atm_set.c new file mode 100644 index 0000000..199c37f --- /dev/null +++ b/sbin/atm/atm/atm_set.c @@ -0,0 +1,540 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_set.c,v 1.12 1998/08/26 23:29:32 mks Exp $ + * + */ + +/* + * User configuration and display program + * -------------------------------------- + * + * Routines for "set" subcommand + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_set.c,v 1.12 1998/08/26 23:29:32 mks Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.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_ioctl.h> + +#include <libatm.h> +#include "atm.h" + + +/* + * Process ATM ARP server set command + * + * Command format: + * atm set arpserver <interface_name> <atm-address> <IP prefix> ... + * + * Arguments: + * argc number of arguments to command + * argv pointer to argument strings + * cmdp pointer to command description + * + * Returns: + * none + * + */ +void +set_arpserver(argc, argv, cmdp) + int argc; + char **argv; + struct cmd *cmdp; +{ + int i, len, prefix_len = 0, rc, s; + char *cp, *intf; + Atm_addr server; + struct sockaddr_in *lis; + struct sockaddr_in if_mask; + struct atmsetreq asr; + struct atminfreq air; + struct air_netif_rsp *int_info; + struct { + struct in_addr ip_addr; + struct in_addr ip_mask; + } prefix_buf[64];; + + /* + * Validate interface name + */ + check_netif_name(argv[0]); + intf = argv[0]; + argc--; argv++; + + /* + * Get the ARP server's ATM address + */ + UM_ZERO(&server, sizeof(server)); + if (strcasecmp(argv[0], "local")) { + /* + * ARP server NSAP address is provided + */ + server.address_format = T_ATM_ENDSYS_ADDR; + server.address_length = sizeof(Atm_addr_nsap); + if (get_hex_atm_addr(argv[0], + (u_char *)server.address, + sizeof(Atm_addr_nsap)) != + sizeof(Atm_addr_nsap)) { + fprintf(stderr, "%s: Invalid ARP server address\n", + prog); + exit(1); + } + if (argc > 1) { + fprintf(stderr, "%s: Invalid number of arguments\n", + prog); + exit(1); + } + prefix_len = 0; + } else { + argc--; argv++; + + /* + * This host is the ARP server + */ + server.address_format = T_ATM_ABSENT; + server.address_length = 0; + + /* + * Get interface information from the kernel. We need + * to get the IP address and the subnet mask associated + * with the network interface and insert them into the + * list of permitted LIS prefixes. + */ + len = sizeof(struct air_netif_rsp); + UM_ZERO(&air, sizeof(air)); + air.air_opcode = AIOCS_INF_NIF; + strcpy(air.air_int_intf, intf); + len = do_info_ioctl(&air, len); + if (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", + intf); + break; + default: + perror("ioctl (AIOCINFO)"); + break; + } + exit(1); + } + int_info = (struct air_netif_rsp *) air.air_buf_addr; + lis = (struct sockaddr_in *)&int_info->anp_proto_addr; + prefix_buf[0].ip_addr = lis->sin_addr; + UM_FREE(int_info); + + rc = get_subnet_mask(intf, &if_mask); + if (rc) { + fprintf(stderr, "%s: Can't get subnet mask for %s\n", + prog, intf); + } + prefix_buf[0].ip_mask = if_mask.sin_addr; + prefix_buf[0].ip_addr.s_addr &= + prefix_buf[0].ip_mask.s_addr; + + /* + * Get the prefixes of the LISs that we'll support + */ + for (i = 1; argc; i++, argc--, argv++) { + rc = parse_ip_prefix(argv[0], + (struct in_addr *)&prefix_buf[i]); + if (rc != 0) { + fprintf(stderr, "%s: Invalid IP prefix value \'%s\'\n", + prog, argv[0]); + exit(1); + } + } + + /* + * Compress the prefix list + */ + prefix_len = compress_prefix_list((struct in_addr *)prefix_buf, + i * sizeof(struct in_addr) * 2); + } + + /* + * Build ioctl request + */ + UM_ZERO(&asr, sizeof(asr)); + asr.asr_opcode = AIOCS_SET_ASV; + strncpy(asr.asr_arp_intf, intf, sizeof(asr.asr_arp_intf)); + asr.asr_arp_addr = server; + asr.asr_arp_subaddr.address_format = T_ATM_ABSENT; + asr.asr_arp_subaddr.address_length = 0; + if (prefix_len) + asr.asr_arp_pbuf = (caddr_t)prefix_buf; + else + asr.asr_arp_pbuf = (caddr_t)0; + asr.asr_arp_plen = prefix_len; + + /* + * Pass the new ARP server address to the kernel + */ + s = socket(AF_ATM, SOCK_DGRAM, 0); + if (s < 0) { + sock_error(errno); + } + if (ioctl(s, AIOCSET, (caddr_t)&asr) < 0) { + fprintf(stderr, "%s: ", prog); + switch (errno) { + case EOPNOTSUPP: + case EPROTONOSUPPORT: + perror("Internal error"); + break; + case EINVAL: + fprintf(stderr, "Invalid parameter\n"); + break; + case ENOMEM: + fprintf(stderr, "Kernel memory exhausted\n"); + break; + case ENETDOWN: + fprintf(stderr, "ATM network is inoperable\n"); + break; + case EPERM: + fprintf(stderr, "Must be super user to use set subcommand\n"); + break; + case ENXIO: + fprintf(stderr, "%s is not an ATM interface\n", intf); + break; + case ENOENT: + fprintf(stderr, "Signalling manager not attached\n"); + break; + case ENOPROTOOPT: + fprintf(stderr, + "%s does not have an IP address configured\n", + intf); + break; + default: + perror("Ioctl (AIOCSET) ARPSERVER address"); + break; + } + exit(1); + } + + (void)close(s); +} + + +/* + * Process set MAC address command + * + * Command format: + * atm set mac <interface_name> <MAC address> + * + * Arguments: + * argc number of remaining arguments to command + * argv pointer to remaining argument strings + * cmdp pointer to command description + * + * Returns: + * none + * + */ +void +set_macaddr(argc, argv, cmdp) + int argc; + char **argv; + struct cmd *cmdp; +{ + int s; + char *intf; + struct mac_addr mac; + struct atmsetreq asr; + + /* + * Validate interface name + */ + if (strlen(argv[0]) > sizeof(asr.asr_mac_intf) - 1) { + fprintf(stderr, "%s: Illegal interface name\n", prog); + exit(1); + } + intf = argv[0]; + argc--; argv++; + + /* + * Get the MAC address provided by the user + */ + if (get_hex_atm_addr(argv[0], (u_char *)&mac, sizeof(mac)) != + sizeof(mac)) { + fprintf(stderr, "%s: Invalid MAC address\n", prog); + exit(1); + } + + /* + * Build ioctl request + */ + asr.asr_opcode = AIOCS_SET_MAC; + strncpy(asr.asr_mac_intf, intf, sizeof(asr.asr_mac_intf)); + UM_COPY(&mac, &asr.asr_mac_addr, sizeof(asr.asr_mac_addr)); + + /* + * Pass the new address to the kernel + */ + s = socket(AF_ATM, SOCK_DGRAM, 0); + if (s < 0) { + sock_error(errno); + } + if (ioctl(s, AIOCSET, (caddr_t)&asr) < 0) { + fprintf(stderr, "%s: ", prog); + switch (errno) { + case EOPNOTSUPP: + case EPROTONOSUPPORT: + perror("Internal error"); + break; + case EADDRINUSE: + fprintf(stderr, "Interface must be detached to set MAC addres\n"); + break; + case EINVAL: + fprintf(stderr, "Invalid parameter\n"); + break; + case ENOMEM: + fprintf(stderr, "Kernel memory exhausted\n"); + break; + case ENETDOWN: + fprintf(stderr, "ATM network is inoperable\n"); + break; + case EPERM: + fprintf(stderr, "Must be super user to use set subcommand\n"); + break; + case ENXIO: + fprintf(stderr, "%s is not an ATM device\n", + argv[0]); + break; + default: + perror("Ioctl (AIOCSET) MAC address"); + break; + } + exit(1); + } + + (void)close(s); +} + + +/* + * Process network interface set command + * + * Command format: + * atm set netif <interface_name> <prefix_name> <count> + * + * Arguments: + * argc number of arguments to command + * argv pointer to argument strings + * cmdp pointer to command description + * + * Returns: + * none + * + */ +void +set_netif(argc, argv, cmdp) + int argc; + char **argv; + struct cmd *cmdp; +{ + struct atmsetreq anr; + char str[16]; + char *cp; + int nifs, s; + + /* + * Set IOCTL opcode + */ + anr.asr_opcode = AIOCS_SET_NIF; + + /* + * Validate interface name + */ + if (strlen(argv[0]) > sizeof(anr.asr_nif_intf) - 1) { + fprintf(stderr, "%s: Illegal interface name\n", prog); + exit(1); + } + strcpy(anr.asr_nif_intf, argv[0]); + argc--; argv++; + + /* + * Validate network interface name prefix + */ + if ((strlen(argv[0]) > sizeof(anr.asr_nif_pref) - 1) || + (strpbrk(argv[0], "0123456789"))) { + fprintf(stderr, "%s: Illegal network interface prefix\n", prog); + exit(1); + } + strcpy(anr.asr_nif_pref, argv[0]); + argc--; argv++; + + /* + * Validate interface count + */ + nifs = (int) strtol(argv[0], &cp, 0); + if ((*cp != '\0') || (nifs < 0) || (nifs > MAX_NIFS)) { + fprintf(stderr, "%s: Invalid interface count\n", prog); + exit(1); + } + anr.asr_nif_cnt = nifs; + + /* + * Make sure the resulting name won't be too long + */ + sprintf(str, "%d", nifs - 1); + if ((strlen(str) + strlen(anr.asr_nif_pref)) > + sizeof(anr.asr_nif_intf) - 1) { + fprintf(stderr, "%s: Network interface prefix too long\n", prog); + exit(1); + } + + /* + * Tell the kernel to do it + */ + s = socket(AF_ATM, SOCK_DGRAM, 0); + if (s < 0) { + sock_error(errno); + } + if (ioctl(s, AIOCSET, (caddr_t)&anr) < 0) { + fprintf(stderr, "%s: ", prog); + perror("ioctl (AIOCSET) set NIF"); + exit(1); + } + (void)close(s); +} + + +/* + * Process set NSAP prefix command + * + * Command format: + * atm set nsap <interface_name> <NSAP prefix> + * + * Arguments: + * argc number of remaining arguments to command + * argv pointer to remaining argument strings + * cmdp pointer to command description + * + * Returns: + * none + * + */ +void +set_prefix(argc, argv, cmdp) + int argc; + char **argv; + struct cmd *cmdp; +{ + int s; + char *intf; + u_char prefix[13]; + struct atmsetreq asr; + + /* + * Validate interface name + */ + if (strlen(argv[0]) > sizeof(asr.asr_prf_intf) - 1) { + fprintf(stderr, "%s: Illegal interface name\n", prog); + exit(1); + } + intf = argv[0]; + argc--; argv++; + + /* + * Get the prefix provided by the user + */ + if (get_hex_atm_addr(argv[0], prefix, sizeof(prefix)) != + sizeof(prefix)) { + fprintf(stderr, "%s: Invalid NSAP prefix\n", prog); + exit(1); + } + + /* + * Build ioctl request + */ + asr.asr_opcode = AIOCS_SET_PRF; + strncpy(asr.asr_prf_intf, intf, sizeof(asr.asr_prf_intf)); + UM_COPY(prefix, asr.asr_prf_pref, sizeof(asr.asr_prf_pref)); + + /* + * Pass the new prefix to the kernel + */ + s = socket(AF_ATM, SOCK_DGRAM, 0); + if (s < 0) { + sock_error(errno); + } + if (ioctl(s, AIOCSET, (caddr_t)&asr) < 0) { + fprintf(stderr, "%s: ", prog); + switch (errno) { + case EOPNOTSUPP: + case EPROTONOSUPPORT: + perror("Internal error"); + break; + case EALREADY: + fprintf(stderr, "NSAP prefix is already set\n"); + break; + case EINVAL: + fprintf(stderr, "Invalid parameter\n"); + break; + case ENOMEM: + fprintf(stderr, "Kernel memory exhausted\n"); + break; + case ENETDOWN: + fprintf(stderr, "ATM network is inoperable\n"); + break; + case EPERM: + fprintf(stderr, "Must be super user to use set subcommand\n"); + break; + case ENXIO: + fprintf(stderr, "%s is not an ATM device\n", + argv[0]); + break; + default: + perror("Ioctl (AIOCSET) NSAP prefix"); + break; + } + exit(1); + } + + (void)close(s); +} diff --git a/sbin/atm/atm/atm_show.c b/sbin/atm/atm/atm_show.c new file mode 100644 index 0000000..8c32dfc --- /dev/null +++ b/sbin/atm/atm/atm_show.c @@ -0,0 +1,1187 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_show.c,v 1.12 1998/07/24 16:20:34 johnc Exp $ + * + */ + +/* + * User configuration and display program + * -------------------------------------- + * + * Routines for "show" subcommand + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_show.c,v 1.12 1998/07/24 16:20:34 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.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_vc.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "atm.h" + + +/* + * Local functions + */ +static int vcc_compare __P((const void *, const void *)); +static int ip_vcc_compare __P((const void *, const void *)); +static int arp_compare __P((const void *, const void *)); + + +/* + * Process show ARP command + * + * Command format: + * atm show ARP [<ip-addr>] + * + * Arguments: + * argc number of remaining arguments to command + * argv pointer to remaining argument strings + * cmdp pointer to command description + * + * Returns: + * none + * + */ +void +show_arp(argc, argv, cmdp) + int argc; + char **argv; + struct cmd *cmdp; +{ + int buf_len, arp_info_len, ip_info_len, sel; + struct atminfreq air; + struct air_arp_rsp *arp_info, *arp_info_base; + struct sockaddr_in *sin; + union { + struct sockaddr_in sin; + struct sockaddr sa; + } host_addr; + + /* + * Get IP address of specified host name + */ + UM_ZERO(&host_addr, sizeof(host_addr)); + host_addr.sa.sa_family = AF_INET; + if (argc) { + sin = get_ip_addr(argv[0]); + if (!sin) { + fprintf(stderr, "%s: host \'%s\' not found\n", + prog, argv[0]); + exit(1); + } + host_addr.sin.sin_addr.s_addr = sin->sin_addr.s_addr; + } else { + host_addr.sin.sin_addr.s_addr = INADDR_ANY; + } + + /* + * Get ARP information from the kernel + */ + UM_ZERO(&air, sizeof(air)); + buf_len = sizeof(struct air_arp_rsp) * 10; + air.air_opcode = AIOCS_INF_ARP; + air.air_arp_addr = host_addr.sa; + arp_info_len = do_info_ioctl(&air, buf_len); + if (arp_info_len < 0) { + fprintf(stderr, "%s: ", prog); + switch (errno) { + case ENOPROTOOPT: + case EOPNOTSUPP: + perror("Internal error"); + break; + case ENXIO: + fprintf(stderr, "not an ATM device\n"); + break; + default: + perror("ioctl (AIOCINFO)"); + break; + } + exit(1); + } + arp_info_base = arp_info = + (struct air_arp_rsp *) air.air_buf_addr; + + /* + * Sort the ARP table + */ + qsort((void *) arp_info, + arp_info_len / sizeof(struct air_arp_rsp), + sizeof(struct air_arp_rsp), + arp_compare); + + /* + * Print the relevant information + */ + while (arp_info_len > 0) { + print_arp_info(arp_info); + arp_info++; + arp_info_len -= sizeof(struct air_arp_rsp); + } + + /* + * Release the information from the kernel + */ + UM_FREE(arp_info_base); +} + + +/* + * Process show ATM ARP server command + * + * Command format: + * atm show arpserver [<interface-name>] + * + * Arguments: + * argc number of remaining arguments to command + * argv pointer to remaining argument strings + * cmdp pointer to command description + * + * Returns: + * none + * + */ +void +show_arpserv(argc, argv, cmdp) + int argc; + char **argv; + struct cmd *cmdp; +{ + int asrv_info_len, buf_len = sizeof(struct air_asrv_rsp) * 3; + struct atminfreq air; + struct air_asrv_rsp *asrv_info, *asrv_info_base; + + /* + * Validate interface name + */ + UM_ZERO(air.air_int_intf, sizeof(air.air_int_intf)); + if (argc) { + if (strlen(argv[0]) > IFNAMSIZ - 1) { + fprintf(stderr, "%s: Illegal interface name\n", + prog); + exit(1); + } + strcpy(air.air_int_intf, argv[0]); + argc--; argv++; + } + + /* + * Get interface information from the kernel + */ + air.air_opcode = AIOCS_INF_ASV; + 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); + } + + /* + * Print the interface information + */ + asrv_info_base = asrv_info = + (struct air_asrv_rsp *) air.air_buf_addr; + for (; buf_len >= sizeof(struct air_asrv_rsp); + asrv_info = (struct air_asrv_rsp *) + ((u_long)asrv_info + asrv_info_len), + buf_len -= asrv_info_len) { + print_asrv_info(asrv_info); + asrv_info_len = sizeof(struct air_asrv_rsp) + + asrv_info->asp_nprefix * + sizeof(struct in_addr) * 2; + } + UM_FREE(asrv_info_base); +} + + +/* + * Process show ATM adapter configuration command + * + * Command format: + * atm show config [<interface-name>] + * + * Arguments: + * argc number of remaining arguments to command + * argv pointer to remaining argument strings + * cmdp pointer to command description + * + * Returns: + * none + * + */ +void +show_config(argc, argv, cmdp) + int argc; + char **argv; + struct cmd *cmdp; +{ + int buf_len = sizeof(struct air_asrv_rsp) * 3; + struct atminfreq air; + struct air_cfg_rsp *cfg_info, *cfg_info_base; + + /* + * Validate interface name + */ + UM_ZERO(air.air_cfg_intf, sizeof(air.air_cfg_intf)); + if (argc) { + if (strlen(argv[0]) > IFNAMSIZ - 1) { + fprintf(stderr, "%s: Illegal interface name\n", + prog); + exit(1); + } + strcpy(air.air_cfg_intf, argv[0]); + argc--; argv++; + } + + /* + * Get configuration information from the kernel + */ + air.air_opcode = AIOCS_INF_CFG; + 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); + } + + /* + * Print the interface information + */ + cfg_info_base = cfg_info = + (struct air_cfg_rsp *) air.air_buf_addr; + for (; buf_len >= sizeof(struct air_cfg_rsp); cfg_info++, + buf_len -= sizeof(struct air_cfg_rsp)) { + print_cfg_info(cfg_info); + } + UM_FREE(cfg_info_base); +} + + +/* + * Process show interface command + * + * Command format: + * atm show interface [<interface-name>] + * + * Arguments: + * argc number of remaining arguments to command + * argv pointer to remaining argument strings + * cmdp pointer to command description + * + * Returns: + * none + * + */ +void +show_intf(argc, argv, cmdp) + int argc; + char **argv; + struct cmd *cmdp; +{ + int buf_len = sizeof(struct air_int_rsp) * 3; + struct atminfreq air; + struct air_int_rsp *int_info, *int_info_base; + + /* + * Validate interface name + */ + UM_ZERO(&air, sizeof(air)); + if (argc) { + if (strlen(argv[0]) > IFNAMSIZ - 1) { + fprintf(stderr, "%s: Illegal interface name\n", + prog); + exit(1); + } + strcpy(air.air_int_intf, argv[0]); + argc--; argv++; + } + + /* + * Get interface information from the kernel + */ + 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); + } + + /* + * Print the interface information + */ + int_info_base = int_info = + (struct air_int_rsp *) air.air_buf_addr; + for (; buf_len >= sizeof(struct air_int_rsp); int_info++, + buf_len -= sizeof(struct air_int_rsp)) { + print_intf_info(int_info); + } + UM_FREE(int_info_base); +} + + +/* + * Process show IP VCCs command + * + * Command format: + * atm show ipvcc [<ip-addr>] + * + * Arguments: + * argc number of remaining arguments to command + * argv pointer to remaining argument strings + * cmdp pointer to command description + * + * Returns: + * none + * + */ +void +show_ip_vcc(argc, argv, cmdp) + int argc; + char **argv; + struct cmd *cmdp; +{ + int buf_len, ip_info_len, rc, sel; + char *if_name = (char *)0; + struct atminfreq air; + struct air_ip_vcc_rsp *ip_info, *ip_info_base; + struct sockaddr_in *sin; + union { + struct sockaddr_in sin; + struct sockaddr sa; + } host_addr; + + /* + * First parameter can be a netif name, an IP host name, or + * an IP address. Figure out which it is. + */ + UM_ZERO(&host_addr, sizeof(host_addr)); + host_addr.sa.sa_family = AF_INET; + if (argc) { + rc = verify_nif_name(argv[0]); + if (rc < 0) { + /* + * Error occured + */ + 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); + } else if (rc > 0) { + /* + * Parameter is a valid netif name + */ + if_name = argv[0]; + } else { + /* + * Get IP address of specified host name + */ + sin = get_ip_addr(argv[0]); + host_addr.sin.sin_addr.s_addr = + sin->sin_addr.s_addr; + } + } else { + host_addr.sin.sin_addr.s_addr = INADDR_ANY; + } + + /* + * Get IP map information from the kernel + */ + buf_len = sizeof(struct air_ip_vcc_rsp) * 10; + air.air_opcode = AIOCS_INF_IPM; + air.air_ip_addr = host_addr.sa; + ip_info_len = do_info_ioctl(&air, buf_len); + if (ip_info_len < 0) { + fprintf(stderr, "%s: ", prog); + switch (errno) { + case ENOPROTOOPT: + case EOPNOTSUPP: + perror("Internal error"); + break; + case ENXIO: + fprintf(stderr, "not an ATM device\n"); + break; + default: + perror("ioctl (AIOCINFO)"); + break; + } + exit(1); + } + ip_info_base = ip_info = + (struct air_ip_vcc_rsp *) air.air_buf_addr; + + /* + * Sort the information + */ + qsort((void *) ip_info, + ip_info_len / sizeof(struct air_ip_vcc_rsp), + sizeof(struct air_ip_vcc_rsp), + ip_vcc_compare); + + /* + * Print the relevant information + */ + while (ip_info_len>0) { + if (!if_name || !strcmp(if_name, ip_info->aip_intf)) { + print_ip_vcc_info(ip_info); + } + ip_info++; + ip_info_len -= sizeof(struct air_ip_vcc_rsp); + } + + /* + * Release the information from the kernel + */ + UM_FREE(ip_info_base); + +} + + +/* + * Process show network interface command + * + * Command format: + * atm show netif [<netif>] + * + * Arguments: + * argc number of remaining arguments to command + * argv pointer to remaining argument strings + * cmdp pointer to command description + * + * Returns: + * none + * + */ +void +show_netif(argc, argv, cmdp) + int argc; + char **argv; + struct cmd *cmdp; +{ + int buf_len = sizeof(struct air_netif_rsp) * 3; + struct atminfreq air; + struct air_netif_rsp *int_info, *int_info_base; + + /* + * Validate network interface name + */ + UM_ZERO(air.air_int_intf, sizeof(air.air_int_intf)); + if (argc) { + if (strlen(argv[0]) > IFNAMSIZ - 1) { + fprintf(stderr, "%s: Illegal interface name\n", prog); + exit(1); + } + strcpy(air.air_int_intf, argv[0]); + argc--; argv++; + } + + /* + * Get network interface information from the kernel + */ + air.air_opcode = AIOCS_INF_NIF; + 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); + } + + /* + * Print the network interface information + */ + int_info_base = int_info = + (struct air_netif_rsp *) air.air_buf_addr; + for (; buf_len >= sizeof(struct air_netif_rsp); int_info++, + buf_len -= sizeof(struct air_netif_rsp)) { + print_netif_info(int_info); + } + UM_FREE(int_info_base); +} + + +/* + * Process interface statistics command + * + * Command format: + * atm show stats interface [<interface-name>] + * + * Arguments: + * argc number of remaining arguments to command + * argv pointer to remaining argument strings + * cmdp pointer to command description + * + * Returns: + * none + * + */ +void +show_intf_stats(argc, argv, cmdp) + int argc; + char **argv; + struct cmd *cmdp; +{ + int buf_len; + char intf[IFNAMSIZ]; + struct atminfreq air; + struct air_phy_stat_rsp *pstat_info, *pstat_info_base; + struct air_cfg_rsp *cfg_info; + + /* + * Validate interface name + */ + UM_ZERO(intf, sizeof(intf)); + if (argc) { + if (strlen(argv[0]) > IFNAMSIZ - 1) { + fprintf(stderr, "%s: Illegal interface name\n", + prog); + exit(1); + } + strcpy(intf, argv[0]); + argc--; argv++; + } + + /* + * If there are parameters remaining, the request is for + * vendor-specific adaptor statistics + */ + if (argc) { + /* + * Get adapter configuration information + */ + buf_len = sizeof(struct air_cfg_rsp); + air.air_opcode = AIOCS_INF_CFG; + strcpy(air.air_cfg_intf, intf); + 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", + intf); + break; + default: + perror("ioctl (AIOCINFO)"); + break; + } + exit(1); + } + cfg_info = (struct air_cfg_rsp *)air.air_buf_addr; + + /* + * Call the appropriate vendor-specific routine + */ + switch(cfg_info->acp_vendor) { + case VENDOR_FORE: + show_fore200_stats(intf, argc, argv); + break; + case VENDOR_ENI: + show_eni_stats(intf, argc, argv); + break; + default: + fprintf(stderr, "%s: Unknown adapter vendor\n", + prog); + break; + } + + UM_FREE(cfg_info); + } else { + /* + * Get generic interface statistics + */ + buf_len = sizeof(struct air_phy_stat_rsp) * 3; + air.air_opcode = AIOCS_INF_PIS; + strcpy(air.air_physt_intf, intf); + 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", + intf); + break; + default: + perror("ioctl (AIOCINFO)"); + break; + } + exit(1); + } + + /* + * Display the interface statistics + */ + pstat_info_base = pstat_info = + (struct air_phy_stat_rsp *)air.air_buf_addr; + for (; buf_len >= sizeof(struct air_phy_stat_rsp); + pstat_info++, + buf_len-=sizeof(struct air_phy_stat_rsp)) { + print_intf_stats(pstat_info); + } + UM_FREE((caddr_t)pstat_info_base); + } +} + + +/* + * Process VCC statistics command + * + * Command format: + * atm show stats VCC [<interface-name> [<vpi> [<vci>]]] + * + * Arguments: + * argc number of remaining arguments to command + * argv pointer to remaining argument strings + * cmdp pointer to command description + * + * Returns: + * none + * + */ +void +show_vcc_stats(argc, argv, cmdp) + int argc; + char **argv; + struct cmd *cmdp; +{ + int vcc_info_len; + int vpi = -1, vci = -1; + char *cp, *intf = NULL; + struct air_vcc_rsp *vcc_info, *vcc_info_base; + + /* + * Validate interface name + */ + if (argc) { + if (strlen(argv[0]) > IFNAMSIZ - 1) { + fprintf(stderr, "%s: Illegal interface name\n", + prog); + exit(1); + } + intf = argv[0]; + argc--; argv++; + } + + /* + * Validate VPI value + */ + if (argc) { + vpi = strtol(argv[0], &cp, 0); + if ((*cp != '\0') || (vpi < 0) || (vpi >= 1 << 8)) { + fprintf(stderr, "%s: Invalid VPI value\n", prog); + exit(1); + } + argc--; argv++; + } + + /* + * Validate VCI value + */ + if (argc) { + vci = strtol(argv[0], &cp, 0); + if ((*cp != '\0') || (vci <= 0) || (vci >= 1 << 16)) { + fprintf(stderr, "%s: Invalid VCI value\n", + prog); + exit(1); + } + argc--; argv++; + } + + /* + * Get VCC information + */ + vcc_info_len = get_vcc_info(intf, &vcc_info); + if (vcc_info_len == 0) + exit(1); + else if (vcc_info_len < 0) { + fprintf(stderr, "%s: ", prog); + switch (errno) { + case ENOPROTOOPT: + case EOPNOTSUPP: + perror("Internal error"); + break; + case ENXIO: + fprintf(stderr, "Not an ATM device\n"); + break; + default: + perror("ioctl (AIOCINFO)"); + break; + } + exit(1); + } + + /* + * Sort the VCC information + */ + qsort((void *) vcc_info, + vcc_info_len / sizeof(struct air_vcc_rsp), + sizeof(struct air_vcc_rsp), + vcc_compare); + + /* + * Display the VCC statistics + */ + vcc_info_base = vcc_info; + for (; vcc_info_len >= sizeof(struct air_vcc_rsp); + vcc_info_len-=sizeof(struct air_vcc_rsp), + vcc_info++) { + if (vpi != -1 && vcc_info->avp_vpi != vpi) + continue; + if (vci != -1 && vcc_info->avp_vci != vci) + continue; + print_vcc_stats(vcc_info); + } + UM_FREE(vcc_info_base); +} + + +/* + * Process VCC information command + * + * Command format: + * atm show VCC [<interface-name> [<vpi> [<vci>] | PVC | SVC]] + * + * Arguments: + * argc number of remaining arguments to command + * argv pointer to remaining argument strings + * cmdp pointer to command description + * + * Returns: + * none + * + */ +void +show_vcc(argc, argv, cmdp) + int argc; + char **argv; + struct cmd *cmdp; +{ + int vcc_info_len; + int vpi = -1, vci = -1, show_pvc = 0, show_svc = 0; + char *cp, *intf = NULL; + struct air_vcc_rsp *vcc_info, *vcc_info_base; + + /* + * Validate interface name + */ + if (argc) { + if (strlen(argv[0]) > IFNAMSIZ - 1) { + fprintf(stderr, "%s: Illegal interface name\n", + prog); + exit(1); + } + intf = argv[0]; + argc--; argv++; + } + + /* + * Validate VPI value + */ + if (argc) { + if (strcasecmp(argv[0], "pvc")) + show_pvc = 1; + else if (strcasecmp(argv[0], "svc")) + show_svc = 1; + else { + vpi = strtol(argv[0], &cp, 0); + if ((*cp != '\0') || (vpi < 0) || + (vpi >= 1 << 8)) { + fprintf(stderr, "%s: Invalid VPI value\n", prog); + exit(1); + } + } + argc--; argv++; + } + + /* + * Validate VCI value + */ + if (argc) { + vci = strtol(argv[0], &cp, 0); + if ((*cp != '\0') || (vci <= 0) || (vci >= 1 << 16)) { + fprintf(stderr, "%s: Invalid VCI value\n", + prog); + exit(1); + } + argc--; argv++; + } + + /* + * Get VCC information + */ + vcc_info_len = get_vcc_info(intf, &vcc_info); + if (vcc_info_len == 0) + exit(1); + else if (vcc_info_len < 0) { + fprintf(stderr, "%s: ", prog); + switch (errno) { + case ENOPROTOOPT: + case EOPNOTSUPP: + perror("Internal error"); + break; + case ENXIO: + fprintf(stderr, "Not an ATM device\n"); + break; + default: + perror("ioctl (AIOCINFO)"); + break; + } + exit(1); + } + + /* + * Sort the VCC information + */ + qsort((void *) vcc_info, + vcc_info_len/sizeof(struct air_vcc_rsp), + sizeof(struct air_vcc_rsp), + vcc_compare); + + /* + * Display the VCC information + */ + vcc_info_base = vcc_info; + for (; vcc_info_len >= sizeof(struct air_vcc_rsp); + vcc_info_len-=sizeof(struct air_vcc_rsp), + vcc_info++) { + if (vpi != -1 && vcc_info->avp_vpi != vpi) + continue; + if (vci != -1 && vcc_info->avp_vci != vci) + continue; + if (show_pvc && vcc_info->avp_type & VCC_PVC) + continue; + if (show_svc && vcc_info->avp_type & VCC_SVC) + continue; + print_vcc_info(vcc_info); + } + UM_FREE(vcc_info_base); +} + + +/* + * Process version command + * + * Command format: + * atm show version + * + * Arguments: + * argc number of remaining arguments to command + * argv pointer to remaining argument strings + * cmdp pointer to command description + * + * Returns: + * none + * + */ +void +show_version(argc, argv, cmdp) + int argc; + char **argv; + struct cmd *cmdp; +{ + int buf_len = sizeof(struct air_version_rsp); + struct atminfreq air; + struct air_version_rsp *ver_info, *ver_info_base; + + /* + * Get network interface information from the kernel + */ + air.air_opcode = AIOCS_INF_VER; + 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, "Not an ATM device\n"); + break; + default: + perror("ioctl (AIOCINFO)"); + break; + } + exit(1); + } + + /* + * Print the network interface information + */ + ver_info_base = ver_info = + (struct air_version_rsp *) air.air_buf_addr; + for (; buf_len >= sizeof(struct air_version_rsp); ver_info++, + buf_len -= sizeof(struct air_version_rsp)) { + print_version_info(ver_info); + } + UM_FREE(ver_info_base); +} + + +/* + * Comparison function for qsort + * + * Arguments: + * p1 pointer to the first VCC response + * p2 pointer to the second VCC response + * + * Returns: + * int a number less than, greater than, or equal to zero, + * depending on whether *p1 is less than, greater than, or + * equal to *p2 + * + */ +static int +vcc_compare(p1, p2) + const void *p1, *p2; +{ + int rc; + struct air_vcc_rsp *c1, *c2; + + c1 = (struct air_vcc_rsp *) p1; + c2 = (struct air_vcc_rsp *) p2; + + /* + * Compare the interface names + */ + rc = strcmp(c1->avp_intf, c2->avp_intf); + if (rc) + return(rc); + + /* + * Compare the VPI values + */ + rc = c1->avp_vpi - c2->avp_vpi; + if (rc) + return(rc); + + /* + * Compare the VCI values + */ + rc = c1->avp_vci - c2->avp_vci; + if (rc) + return(rc); + + /* + * Compare the types + */ + rc = c1->avp_type - c2->avp_type; + return(rc); +} + + +/* + * Comparison function for qsort + * + * Arguments: + * p1 pointer to the first VCC response + * p2 pointer to the second VCC response + * + * Returns: + * int a number less than, greater than, or equal to zero, + * depending on whether *p1 is less than, greater than, or + * equal to *p2 + * + */ +static int +ip_vcc_compare(p1, p2) + const void *p1, *p2; +{ + int rc; + struct air_ip_vcc_rsp *c1, *c2; + + c1 = (struct air_ip_vcc_rsp *) p1; + c2 = (struct air_ip_vcc_rsp *) p2; + + /* + * Compare the interface names + */ + rc = strcmp(c1->aip_intf, c2->aip_intf); + if (rc) + return(rc); + + /* + * Compare the VPI values + */ + rc = c1->aip_vpi - c2->aip_vpi; + if (rc) + return(rc); + + /* + * Compare the VCI values + */ + rc = c1->aip_vci - c2->aip_vci; + return(rc); +} + + +/* + * Comparison function for qsort + * + * Arguments: + * p1 pointer to the first ARP or IP map entry + * p2 pointer to the second ARP or IP map entry + * + * Returns: + * int a number less than, greater than, or equal to zero, + * depending on whether *p1 is less than, greater than, or + * equal to *p2 + * + */ +static int +arp_compare(p1, p2) + const void *p1, *p2; +{ + int rc; + struct air_arp_rsp *c1, *c2; + struct sockaddr_in *sin1, *sin2; + + c1 = (struct air_arp_rsp *) p1; + c2 = (struct air_arp_rsp *) p2; + sin1 = (struct sockaddr_in *) &c1->aap_arp_addr; + sin2 = (struct sockaddr_in *) &c2->aap_arp_addr; + + /* + * Compare the IP addresses + */ + if (rc = sin1->sin_family - sin2->sin_family) + return(rc); + if (rc = sin1->sin_addr.s_addr - sin2->sin_addr.s_addr) + return(rc); + + /* + * Compare the ATM addresses + */ + if (rc = c1->aap_addr.address_format - c2->aap_addr.address_format) + return(rc); + if (rc = c1->aap_addr.address_length - c2->aap_addr.address_length) + return(rc); + switch(c1->aap_addr.address_format) { + case T_ATM_ABSENT: + rc = 0; + break; + case T_ATM_ENDSYS_ADDR: + rc = bcmp((caddr_t)c1->aap_addr.address, + (caddr_t)c2->aap_addr.address, + sizeof(Atm_addr_nsap)); + break; + case T_ATM_E164_ADDR: + rc = bcmp((caddr_t)c1->aap_addr.address, + (caddr_t)c2->aap_addr.address, + sizeof(Atm_addr_e164)); + break; + case T_ATM_SPANS_ADDR: + rc = bcmp((caddr_t)c1->aap_addr.address, + (caddr_t)c2->aap_addr.address, + sizeof(Atm_addr_spans)); + break; + } + + return(rc); +} diff --git a/sbin/atm/atm/atm_subr.c b/sbin/atm/atm/atm_subr.c new file mode 100644 index 0000000..4571173 --- /dev/null +++ b/sbin/atm/atm/atm_subr.c @@ -0,0 +1,620 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_subr.c,v 1.11 1998/07/09 22:24:03 johnc Exp $ + * + */ + +/* + * User configuration and display program + * -------------------------------------- + * + * General subroutines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_subr.c,v 1.11 1998/07/09 22:24:03 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/socket.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_ioctl.h> + +#include <libatm.h> +#include "atm.h" + + +/* + * Table entry definition + */ +typedef struct { + int type; + char *name; +} tbl_ent; + + +/* + * Table to translate vendor codes to ASCII + */ +tbl_ent vendors[] = { + { VENDAPI_UNKNOWN, "Unknown" }, + { VENDAPI_FORE_1, "Fore" }, + { VENDAPI_ENI_1, "ENI" }, + { 0, 0 }, +}; + + +/* + * Table to translate adapter codes to ASCII + */ +tbl_ent adapter_types[] = { + { DEV_UNKNOWN, "Unknown" }, + { DEV_FORE_SBA200E, "SBA-200E" }, + { DEV_FORE_SBA200, "SBA-200" }, + { DEV_FORE_PCA200E, "PCA-200E" }, + { DEV_ENI_155P, "ENI-155p" }, + { 0, 0 }, +}; + +/* + * Table to translate medium types to ASCII + */ +tbl_ent media_types[] = { + { MEDIA_UNKNOWN, "Unknown" }, + { MEDIA_TAXI_100, "100 Mbps 4B/5B" }, + { MEDIA_TAXI_140, "140 Mbps 4B/5B" }, + { MEDIA_OC3C, "OC-3c" }, + { MEDIA_OC12C, "OC-12c" }, + { MEDIA_UTP155, "155 Mbps UTP" }, + { 0, 0 }, +}; + +/* + * Table to translate bus types to ASCII + */ +tbl_ent bus_types[] = { + { BUS_UNKNOWN, "Unknown" }, + { BUS_SBUS_B16, "SBus" }, + { BUS_SBUS_B32, "SBus" }, + { BUS_PCI, "PCI" }, + { 0, 0 }, +}; + + +/* + * Get interface vendor name + * + * Return a character string with a vendor name, given a vendor code. + * + * Arguments: + * vendor vendor ID + * + * Returns: + * char * pointer to a string with the vendor name + * + */ +char * +get_vendor(vendor) + int vendor; +{ + int i; + + for(i=0; vendors[i].name; i++) { + if (vendors[i].type == vendor) + return(vendors[i].name); + } + + return("-"); +} + + +/* + * Get adapter type + * + * Arguments: + * dev adapter code + * + * Returns: + * char * pointer to a string with the adapter type + * + */ +char * +get_adapter(dev) + int dev; +{ + int i; + + for(i=0; adapter_types[i].name; i++) { + if (adapter_types[i].type == dev) + return(adapter_types[i].name); + } + + return("-"); +} + + +/* + * Get communication medium type + * + * Arguments: + * media medium code + * + * Returns: + * char * pointer to a string with the name of the medium + * + */ +char * +get_media_type(media) + int media; +{ + int i; + + for(i=0; media_types[i].name; i++) { + if (media_types[i].type == media) + return(media_types[i].name); + } + + return("-"); +} + + +/* + * Get bus type + * + * Arguments: + * bus bus type code + * + * Returns: + * char * pointer to a string with the bus type + * + */ +char * +get_bus_type(bus) + int bus; +{ + int i; + + for(i=0; bus_types[i].name; i++) { + if (bus_types[i].type == bus) + return(bus_types[i].name); + } + + return("-"); +} + + +/* + * Get adapter ID + * + * Get a string giving the adapter's vendor and type. + * + * Arguments: + * intf interface name + * + * Returns: + * char * pointer to a string identifying the adapter + * + */ +char * +get_adapter_name(intf) + char *intf; +{ + int buf_len; + struct atminfreq air; + struct air_cfg_rsp *cfg; + static char name[256]; + + /* + * Initialize + */ + UM_ZERO(&air, sizeof(air)); + UM_ZERO(name, sizeof(name)); + + /* + * Get configuration information from the kernel + */ + air.air_opcode = AIOCS_INF_CFG; + strcpy(air.air_cfg_intf, intf); + buf_len = do_info_ioctl(&air, sizeof(struct air_cfg_rsp)); + if (buf_len < sizeof(struct air_cfg_rsp)) + return("-"); + cfg = (struct air_cfg_rsp *) air.air_buf_addr; + + /* + * Build a string describing the adapter + */ + strcpy(name, get_vendor(cfg->acp_vendor)); + strcat(name, " "); + strcat(name, get_adapter(cfg->acp_device)); + + UM_FREE(cfg); + + return(name); +} + + +/* + * Format a MAC address into a string + * + * Arguments: + * addr pointer to a MAC address + * + * Returns: + * the address of a string representing the MAC address + * + */ +char * +format_mac_addr(addr) + Mac_addr *addr; +{ + static char str[256]; + + /* + * Check for null pointer + */ + if (!addr) + return("-"); + + /* + * Clear the returned string + */ + UM_ZERO(str, sizeof(str)); + + /* + * Format the address + */ + sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x", + addr->ma_data[0], + addr->ma_data[1], + addr->ma_data[2], + addr->ma_data[3], + addr->ma_data[4], + addr->ma_data[5]); + + return(str); +} + + +/* + * Parse an IP prefix designation in the form nnn.nnn.nnn.nnn/mm + * + * Arguments: + * cp pointer to prefix designation string + * op pointer to a pair of in_addrs for the result + * + * Returns: + * 0 success + * -1 prefix was invalid + * + */ +int +parse_ip_prefix(cp, op) + char *cp; + struct in_addr *op; +{ + int i, len; + char *mp; + struct in_addr ip_addr; + + static u_long masks[33] = { + 0x0, + 0x80000000, + 0xc0000000, + 0xe0000000, + 0xf0000000, + 0xf8000000, + 0xfc000000, + 0xfe000000, + 0xff000000, + 0xff800000, + 0xffc00000, + 0xffe00000, + 0xfff00000, + 0xfff80000, + 0xfffc0000, + 0xfffe0000, + 0xffff0000, + 0xffff8000, + 0xffffc000, + 0xffffe000, + 0xfffff000, + 0xfffff800, + 0xfffffc00, + 0xfffffe00, + 0xffffff00, + 0xffffff80, + 0xffffffc0, + 0xffffffe0, + 0xfffffff0, + 0xfffffff8, + 0xfffffffc, + 0xfffffffe, + 0xffffffff + }; + + /* + * Find the slash that marks the start of the mask + */ + mp = strchr(cp, '/'); + if (mp) { + *mp = '\0'; + mp++; + } + + /* + * Convert the IP-address part of the prefix + */ + ip_addr.s_addr = inet_addr(cp); + if (ip_addr.s_addr == -1) + return(-1); + + /* + * Set the default mask length + */ + if (IN_CLASSA(ntohl(ip_addr.s_addr))) + len = 8; + else if (IN_CLASSB(ntohl(ip_addr.s_addr))) + len = 16; + else if (IN_CLASSC(ntohl(ip_addr.s_addr))) + len = 24; + else + return(-1); + + /* + * Get the mask length + */ + if (mp) { + len = atoi(mp); + if (len < 1 || len > 32) + return(-1); + } + + /* + * Select the mask and copy the IP address into the + * result buffer, ANDing it with the mask + */ + op[1].s_addr = htonl(masks[len]); + op[0].s_addr = ip_addr.s_addr & op[1].s_addr; + + return(0); +} + + +/* + * Compress a list of IP network prefixes + * + * Arguments: + * ipp pointer to list of IP address/mask pairs + * ipc length of list + * + * Returns: + * length of compressed list + * + */ +int +compress_prefix_list(ipp, ilen) + struct in_addr *ipp; + int ilen; +{ + int i, j, n; + struct in_addr *ip1, *ip2, *m1, *m2; + + /* + * Figure out how many pairs there are + */ + n = ilen / (sizeof(struct in_addr) * 2); + + /* + * Check each pair of address/mask pairs to make sure + * none contains the other + */ + for (i = 0; i < n; i++) { + ip1 = &ipp[i*2]; + m1 = &ipp[i*2+1]; + + /* + * If we've already eliminated this address, + * skip the checks + */ + if (ip1->s_addr == 0) + continue; + + /* + * Try all possible second members of the pair + */ + for (j = i + 1; j < n; j++) { + ip2 = &ipp[j*2]; + m2 = &ipp[j*2+1]; + + /* + * If we've already eliminated the second + * address, just skip the checks + */ + if (ip2->s_addr == 0) + continue; + + /* + * Compare the address/mask pairs + */ + if (m1->s_addr == m2->s_addr) { + /* + * Masks are equal + */ + if (ip1->s_addr == ip2->s_addr) { + ip2->s_addr = 0; + m2->s_addr = 0; + } + } else if (ntohl(m1->s_addr) < + ntohl(m2->s_addr)) { + /* + * m1 is shorter + */ + if ((ip2->s_addr & m1->s_addr) == + ip1->s_addr) { + ip2->s_addr = 0; + m2->s_addr = 0; + } + } else { + /* + * m1 is longer + */ + if (ip1->s_addr & m2->s_addr == + ip2->s_addr) { + ip1->s_addr = 0; + m1->s_addr = 0; + break; + } + } + } + } + + /* + * Now pull up the list, eliminating zeroed entries + */ + for (i = 0, j = 0; i < n; i++) { + ip1 = &ipp[i*2]; + m1 = &ipp[i*2+1]; + ip2 = &ipp[j*2]; + m2 = &ipp[j*2+1]; + if (ip1->s_addr != 0) { + if (i != j) { + *ip2 = *ip1; + *m2 = *m1; + } + j++; + } + } + + return(j * sizeof(struct in_addr) * 2); +} + + +/* + * Make sure a user-supplied parameter is a valid network interface + * name + * + * When a socket call fails, print an error message and exit + * + * Arguments: + * nif pointer to network interface name + * + * Returns: + * none exits if name is not valid + * + */ +void +check_netif_name(nif) + char *nif; +{ + int rc; + + /* + * Look up the name in the kernel + */ + rc = verify_nif_name(nif); + + /* + * Check the result + */ + if (rc > 0) { + /* + * Name is OK + */ + return; + } else if (rc == 0) { + /* + * Name is not valid + */ + fprintf(stderr, "%s: Invalid network interface name %s\n", + prog, nif); + } else { + /* + * Error performing IOCTL + */ + 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", + nif); + break; + default: + perror("ioctl (AIOCINFO)"); + break; + } + } + + exit(1); +} + + +/* + * Socket error handler + * + * When a socket call fails, print an error message and exit + * + * Arguments: + * err an errno describing the error + * + * Returns: + * none + * + */ +void +sock_error(err) + int err; +{ + fprintf(stderr, "%s: ", prog); + + switch (err) { + + case EPROTONOSUPPORT: + fprintf(stderr, "ATM protocol support not loaded\n"); + break; + + default: + perror("socket"); + break; + } + + exit(1); +} diff --git a/sbin/atm/fore_dnld/Makefile b/sbin/atm/fore_dnld/Makefile new file mode 100644 index 0000000..ac7c3a2 --- /dev/null +++ b/sbin/atm/fore_dnld/Makefile @@ -0,0 +1,36 @@ +# +# +# =================================== +# 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. +# +# @(#) $Id: Makefile,v 1.5 1998/07/10 16:01:58 jpt Exp $ +# +# + +PROG= fore_dnld +MAN8= fore_dnld.8 + +CFLAGS+= -I ${.CURDIR}/../../../sys +LDADD+= -latm + +.include <bsd.prog.mk> diff --git a/sbin/atm/fore_dnld/fore_dnld.8 b/sbin/atm/fore_dnld/fore_dnld.8 new file mode 100644 index 0000000..770f85d --- /dev/null +++ b/sbin/atm/fore_dnld/fore_dnld.8 @@ -0,0 +1,108 @@ +.\" +.\" =================================== +.\" 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. +.\" +.\" @(#) $Id: fore_dnld.1,v 1.4 1997/05/09 17:29:37 mks Exp $ +.\" +.\" +.de EX \"Begin example +.ne 5 +.if n .sp 1 +.if t .sp .5 +.nf +.in +.5i +.. +.de EE +.fi +.in -.5i +.if n .sp 1 +.if t .sp .5 +.. +.TH FORE_DNLD 8 "1996-12-03" "HARP" +.SH NAME +fore_dnld \- Download FORE Systems' microcode into host ATM adapter +.SH SYNOPSIS +.B fore_dnld +[-i intf] +[-d path] +[-f objfile] +.sp +.fi +.SH DESCRIPTION +.I fore_dnld +downloads FORE Systems' microcode into the host ATM adapter(s). +.fi +.SH OPTIONS +.TP +.B \-i intf +Specify which ATM interface to download microcode to. +Default is to load microcode into all FORE Systems host adapters. +.TP +.B -d path +Specify the path to prepend to the "objfile" name. +Default is to use current directory. +.TP +.B -f objfile +Specify the microcode binary file. Defaults are: +"sba200.obj" for SBA-200 adapters, +"sba200e.obj" for SBA-200E adapters, and +"pca200e.bin" for PCA-200E adapters. +.fi +.SH NOTES +.PP +Microcode as distributed by FORE Systems is not ready for downloading +directly into SBA host ATM adapters. Instead, the supplied microcode needs +to be processed with the "objcopy" command to create an image suitable +for downloading. Arguments to "objcopy" are "-S -l -Fcoff". Microcode as +distibuted by FORE Systems for the PCA host ATM adapter does not need +to be processed. +.SH "SEE ALSO" +.PP +~fore/etc/objcopy - command to process FORE Systems supplied microcode. +.PP +~fore/etc/sba200*.ucode* - microcode as supplied by FORE Systems for SBA +adapters. +.PP +~fore/i386/pca200e.bin - microcode as supplied by FORE Systems for PCA +adapters. +.PP +~harp/doc/Install - HARP installation instructions. +.fi +.SH BUGS +.PP +None known. +.fi +.SH COPYRIGHT +Copyright (c) 1994-1998, Network Computing Services, Inc. +.fi +.SH AUTHORS +John Cavanaugh, Minnesota Supercomputer Center, Inc. +.br +Mike Spengler, Minnesota Supercomputer Center, Inc. +.br +Joe Thomas, Minnesota Supercomputer Center, Inc. +.fi +.SH ACKNOWLEDGMENTS +This software was developed under the sponsorship of the +Defense Advanced Research Projects Agency (DARPA) under +contract numbers F19628-92-C-0072 and F19628-95-C-0215. diff --git a/sbin/atm/fore_dnld/fore_dnld.c b/sbin/atm/fore_dnld/fore_dnld.c new file mode 100644 index 0000000..6ecafa5 --- /dev/null +++ b/sbin/atm/fore_dnld/fore_dnld.c @@ -0,0 +1,1245 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_dnld.c,v 1.15 1998/08/26 23:29:32 mks Exp $ + * + */ + +/* + * User utilities + * -------------- + * + * Download (pre)processed microcode into Fore Series-200 host adapter + * Interact with i960 uart on Fore Series-200 host adapter + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: fore_dnld.c,v 1.15 1998/08/26 23:29:32 mks Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <sys/socket.h> +#include <net/if.h> +#include <sys/stat.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <dev/hfa/fore.h> +#include <dev/hfa/fore_aali.h> +#include <dev/hfa/fore_slave.h> + +#if (defined(BSD) && (BSD >= 199103)) +#include <termios.h> +#else +#include <termio.h> +#endif /* !BSD */ + +#ifdef sun +#define DEV_NAME "/dev/sbus%d" +#endif /* sun */ +#if (defined(BSD) && (BSD >= 199103)) +#define DEV_NAME "/dev/kmem" +#endif /* BSD */ + +#define MAX_CHECK 60 + +int comm_mode = 0; +char *progname; + +int tty; +cc_t vmin, vtime; +#if (defined(BSD) && (BSD >= 199103)) +struct termios sgtty; +#define TCSETA TIOCSETA +#define TCGETA TIOCGETA +#else +struct termio sgtty; +#endif /* !BSD */ + +int endian = 0; +int verbose = 0; +int reset = 0; + +char line[132]; +int lineptr = 0; + +Mon960 *Uart; + +delay(cnt) + int cnt; +{ + usleep(cnt); +} + +unsigned long +CP_READ ( val ) +unsigned long val; +{ + if ( endian ) + return ( ntohl ( val ) ); + else + return ( val ); +} + +unsigned long +CP_WRITE ( val ) +unsigned long val; +{ + if ( endian ) + return ( htonl ( val ) ); + else + return ( val ); +} + +/* + * Print an error message and exit. + * + * Arguments: + * none + * + * Returns: + * none + */ +void +error ( msg ) +char *msg; +{ + printf ( "%s\n", msg ); + exit (1); +} + +/* + * Get a byte for the uart and if printing, display it. + * + * Arguments: + * prn Are we displaying characters + * + * Returns: + * c Character from uart + */ +char +getbyte ( prn ) +int prn; +{ + int c; + + while ( ! ( CP_READ(Uart->mon_xmithost) & UART_VALID ) ) + delay(10); + + c = ( CP_READ(Uart->mon_xmithost) & UART_DATAMASK ); + Uart->mon_xmithost = CP_WRITE(UART_READY); + + /* + * We need to introduce a delay in here or things tend to hang... + */ + delay(10); + + if ( lineptr >= sizeof(line) ) + lineptr = 0; + + /* + * Save character into line + */ + line[lineptr++] = c; + + if (verbose) { + if (isprint(c) || (c == '\n') || (c == '\r')) + putc(c, stdout); + } + return ( c & 0xff ); +} + +/* + * Loop getting characters from uart into static string until eol. If printing, + * display the line retrieved. + * + * Arguments: + * prn Are we displaying characters + * + * Returns: + * none Line in global string 'line[]' + */ +void +getline ( prn ) +int prn; +{ + char c = '\0'; + int i = 0; + + while ( c != '>' && c != '\n' && c != '\r' ) + { + c = getbyte(0); + if ( ++i >= sizeof(line) ) + { + if ( prn ) + printf ( "%s", line ); + i = 0; + } + } + + /* + * Terminate line + */ + line[lineptr] = 0; + lineptr = 0; + +} + +/* + * Send a byte to the i960 + * + * Arguments: + * c Character to send + * + * Returns: + * none + */ +void +xmit_byte ( c, dn ) +unsigned char c; +int dn; +{ + int val; + + while ( CP_READ(Uart->mon_xmitmon) != UART_READY ) + { + if ( CP_READ(Uart->mon_xmithost) & UART_VALID ) + getbyte ( 0 ); + if ( !dn ) delay ( 1000 ); + } + val = ( c | UART_VALID ); + Uart->mon_xmitmon = CP_WRITE( val ); + +} + +/* + * Transmit a line to the i960. Eol must be included as part of text to transmit. + * + * Arguments: + * line Character string to transmit + * len len of string. This allows us to include NULL's + * in the string/block to be transmitted. + * + * Returns: + * none + */ +xmit_to_i960 ( line, len, dn ) +char *line; +int len; +int dn; +{ + int i; + + for ( i = 0; i < len; i++ ) + xmit_byte ( line[i], dn ); +} + +/* + * Send autobaud sequence to i960 monitor + * + * Arguments: + * none + * + * Returns: + * none + */ +void +autobaud() +{ + if ( strncmp ( line, "Mon960", 6 ) == 0 ) + xmit_to_i960 ( "\r\n\r\n\r\n\r\n", 8, 0 ); +} + +/* + * Reset tty to initial state + * + * Arguments: + * ret error code for exit() + * + * Returns: + * none + * + */ +void +finish ( ret ) +{ + sgtty.c_lflag |= ( ICANON | ECHO ); + sgtty.c_cc[VMIN] = vmin; + sgtty.c_cc[VTIME] = vtime; + ioctl ( tty, TCSETA, &sgtty ); + exit ( ret ); +} + +/* + * Utility to strip off any leading path information from a filename + * + * Arguments: + * path pathname to strip + * + * Returns: + * fname striped filename + * + */ +char * +basename ( path ) + char *path; +{ + char *fname; + + if ( ( fname = strrchr ( path, '/' ) ) != NULL ) + fname++; + else + fname = path; + + return ( fname ); +} + +/* + * ASCII constants + */ +#define SOH 001 +#define STX 002 +#define ETX 003 +#define EOT 004 +#define ENQ 005 +#define ACK 006 +#define LF 012 +#define CR 015 +#define NAK 025 +#define SYN 026 +#define CAN 030 +#define ESC 033 + +#define NAKMAX 2 +#define ERRORMAX 10 +#define RETRYMAX 5 + +#define CRCCHR 'C' +#define CTRLZ 032 + +#define BUFSIZE 128 + +#define W 16 +#define B 8 + +/* + * crctab - CRC-16 constant array... + * from Usenet contribution by Mark G. Mendel, Network Systems Corp. + * (ihnp4!umn-cs!hyper!mark) + */ +unsigned short crctab[1<<B] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 + }; + +/* + * Hacked up xmodem protocol. Transmits the file 'filename' down to the i960 + * using the xmodem protocol. + * + * Arguments: + * filename name of file to transmit + * + * Returns: + * 0 file transmitted + * -1 unable to send file + */ +int +sendfile ( filename ) +char *filename; +{ + int fd; + int numsect; + int sectnum; + struct stat stb; + char c; + char sendresp; + int crcmode = 0; + int attempts = 0; + int errors; + int sendfin; + int extrachr; + char buf[BUFSIZE + 6]; + char blockbuf[BUFSIZE + 6]; + int bufcntr; + int bbufcntr; + int bufsize = BUFSIZE; + int checksum; + + /* + * Try opening file + */ + if ( ( fd = open ( filename, O_RDONLY ) ) < 0 ) + { + return -1; + } + stat ( filename, &stb ); + + /* + * Determine number of 128 bytes sectors to transmit + */ + numsect = ( stb.st_size / 128 ) + 1; + + if ( verbose ) + fprintf ( stderr, "Downloading %d sectors from %s\n", + numsect, filename ); + + /* + * Send DO'wnload' command to i960 + */ + xmit_to_i960 ( "do\r\n", 4, 0 ); + /* + * Wait for response from i960 indicating download in progress + */ + while ( strncmp ( line, "Downloading", 11 ) != 0 ) + getline ( verbose ); + + + /* + * Get startup character from i960 + */ + do { + while ( ( c = getbyte(0) ) != NAK && c != CRCCHR ) + if ( ++attempts > NAKMAX ) + error ( "Remote system not responding" ); + + if ( c == CRCCHR ) + crcmode = 1; + + } while ( c != NAK && c != CRCCHR ); + + sectnum = 1; + attempts = errors = sendfin = extrachr = 0; + + /* + * Loop over each sector to be sent + */ + do { + if ( extrachr >= 128 ) + { + extrachr = 0; + numsect++; + } + + if ( sectnum > 0 ) + { + /* + * Read a sectors worth of data from the file into + * an internal buffer. + */ + for ( bufcntr = 0; bufcntr < bufsize; ) + { + int n; + /* + * Check for EOF + */ + if ( ( n = read ( fd, &c, 1 ) ) == 0 ) + { + sendfin = 1; + if ( !bufcntr ) + break; + buf[bufcntr++] = CTRLZ; + continue; + } + buf[bufcntr++] = c; + } + if ( !bufcntr ) + break; + } + + /* + * Fill in xmodem protocol values. Block size and sector number + */ + bbufcntr = 0; + blockbuf[bbufcntr++] = (bufsize == 1024) ? STX : SOH; + blockbuf[bbufcntr++] = sectnum; + blockbuf[bbufcntr++] = ~sectnum; + + checksum = 0; + + /* + * Loop over the internal buffer computing the checksum of the + * sector + */ + for ( bufcntr = 0; bufcntr < bufsize; bufcntr++ ) + { + blockbuf[bbufcntr++] = buf[bufcntr]; + + if ( crcmode ) + checksum = (checksum<<B) ^ crctab[(checksum>>(W-B)) ^ buf[bufcntr]]; + else + checksum = ((checksum + buf[bufcntr]) & 0xff); + + } + + /* + * Place the checksum at the end of the transmit buffer + */ + if ( crcmode ) + { + checksum &= 0xffff; + blockbuf[bbufcntr++] = ((checksum >> 8) & 0xff); + blockbuf[bbufcntr++] = (checksum & 0xff); + } else + blockbuf[bbufcntr++] = checksum; + + attempts = 0; + + /* + * Make several attempts to send the data to the i960 + */ + do + { + /* + * Transmit the sector + protocol to the i960 + */ + xmit_to_i960 ( blockbuf, bbufcntr, 1 ); + + /* + * Inform user where we're at + */ + if ( verbose ) + printf ( "Sector %3d %3dk\r", + sectnum, (sectnum * bufsize) / 1024 ); + + attempts++; + /* + * Get response from i960 + */ + sendresp = getbyte(0); + + /* + * If i960 didn't like the sector + */ + if ( sendresp != ACK ) + { + errors++; + + /* + * Are we supposed to cancel the transfer? + */ + if ( ( sendresp & 0x7f ) == CAN ) + if ( getbyte(0) == CAN ) + error ( "Send canceled at user's request" ); + } + + } while ( ( sendresp != ACK ) && ( attempts < RETRYMAX ) && ( errors < ERRORMAX ) ); + + /* + * Next sector + */ + sectnum++; + + } while ( !sendfin && ( attempts < RETRYMAX ) && ( errors < ERRORMAX ) ); + + /* + * Did we expire all our allows attempts? + */ + if ( attempts >= RETRYMAX ) + { + xmit_byte ( CAN, 1 ), xmit_byte ( CAN, 1 ), xmit_byte ( CAN, 1 ); + error ( "Remote system not responding" ); + } + + /* + * Check for too many transmission errors + */ + if ( errors >= ERRORMAX ) + { + xmit_byte ( CAN, 1 ), xmit_byte ( CAN, 1 ), xmit_byte ( CAN, 1 ); + error ( "Too many errors in transmission" ); + } + + attempts = 0; + + /* + * Indicate the transfer is complete + */ + xmit_byte ( EOT, 1 ); + + /* + * Wait until i960 acknowledges us + */ + while ( ( c = getbyte(0) ) != ACK && ( ++attempts < RETRYMAX ) ) + xmit_byte ( EOT, 1 ); + + if ( attempts >= RETRYMAX ) + error ( "Remote system not responding on completion" ); + + /* + * After download, we'll see a few more command + * prompts as the CP does its stuff. Ignore them. + */ + while ( strncmp ( line, "=>", 2 ) != 0 ) + getline ( verbose ); + + while ( strncmp ( line, "=>", 2 ) != 0 ) + getline ( verbose ); + + while ( strncmp ( line, "=>", 2 ) != 0 ) + getline ( verbose ); + + /* + * Tell the i960 to start executing the downloaded code + */ + xmit_to_i960 ( "go\r\n", 4, 0 ); + + /* + * Get the messages the CP will spit out + * after the GO command. + */ + getline ( verbose ); + getline ( verbose ); + + close ( fd ); + + return ( 0 ); +} + + +int +sendbinfile ( fname, ram ) +char *fname; +u_char *ram; +{ + struct { + u_long Id; + u_long fver; + u_long start; + u_long entry; + } binhdr; + union { + u_long w; + char c[4]; + } w1, w2; + int fd; + int n; + int cnt = 0; + u_char *bufp; + long buffer[1024]; + + /* + * Try opening file + */ + if ( ( fd = open ( fname, O_RDONLY ) ) < 0 ) + return ( -1 ); + + /* + * Read the .bin header from the file + */ + if ( ( read ( fd, &binhdr, sizeof(binhdr) ) ) != sizeof(binhdr) ) + { + close ( fd ); + return ( -1 ); + } + + /* + * Check that we understand this header + */ + if ( strncmp ( (caddr_t)&binhdr.Id, "fore", 4 ) != 0 ) { + fprintf ( stderr, "Unrecognized format in micorcode file." ); + close ( fd ); + return ( -1 ); + } + +#ifdef sun + /* + * We always swap the SunOS microcode file... + */ + endian = 1; + + /* + * We need to swap the header start/entry words... + */ + w1.w = binhdr.start; + for ( n = 0; n < sizeof(u_long); n++ ) + w2.c[3-n] = w1.c[n]; + binhdr.start = w2.w; + w1.w = binhdr.entry; + for ( n = 0; n < sizeof(u_long); n++ ) + w2.c[3-n] = w1.c[n]; + binhdr.entry = w2.w; +#endif /* sun */ + + /* + * Rewind the file + */ + lseek ( fd, 0, 0 ); + + /* + * Set pointer to RAM load location + */ + bufp = (ram + binhdr.start); + + /* + * Load file + */ + if ( endian ) { + /* + * Need to swap longs - copy file into temp buffer + */ + while ( ( n = read ( fd, (char *)buffer, sizeof(buffer))) > 0 ) + { + int i; + + /* Swap buffer */ + for ( i = 0; i < sizeof(buffer) / sizeof(long); i++ ) +#ifndef sun + buffer[i] = CP_WRITE(buffer[i]); +#else + { + int j; + + w1.w = buffer[i]; + for ( j = 0; j < 4; j++ ) + w2.c[3-j] = w1.c[j]; + buffer[i] = w2.w; + } +#endif + + /* + * Copy swapped buffer into CP RAM + */ + cnt++; + bcopy ( (caddr_t)buffer, bufp, n ); + if ( verbose ) + printf ( "%d\r", cnt ); + bufp += n; + } + } else { + while ( ( n = read ( fd, bufp, 128 ) ) > 0 ) + { + cnt++; + if ( verbose ) + printf ( "%d\r", cnt ); + bufp += n; + } + } + + /* + * With .bin extension, we need to specify start address on 'go' + * command. + */ + { + char cmd[80]; + char c; + + sprintf ( cmd, "go %x\r\n", binhdr.entry ); + + xmit_to_i960 ( cmd, strlen ( cmd ), 0 ); + + while ( strncmp ( line, cmd, strlen(cmd) - 3 ) != 0 ) + getline ( verbose ); + + if ( verbose ) + printf("\n"); + } + + close ( fd ); + return ( 0 ); +} + + +/* + * Program to download previously processed microcode to series-200 host adapter + */ +main( argc, argv ) +int argc; +char *argv[]; +{ + int fd; /* mmap for Uart */ + u_char *ram; /* pointer to RAM */ + Mon960 *Mon; /* Uart */ + Aali *aap; + char c; + int i, err; + int binary = 0; /* Send binary file */ + caddr_t buf; /* Ioctl buffer */ + Atm_config *adp; /* Adapter config */ + char bus_dev[80]; /* Bus device to mmap on */ + struct atminfreq req; + struct air_cfg_rsp *air; /* Config info response structure */ + int buf_len; /* Size of ioctl buffer */ + char *devname = "\0"; /* Device to download */ + char *dirname = NULL; /* Directory path to objd files */ + char *objfile = NULL; /* Command line object filename */ + char *sndfile; /* Object filename to download */ + char filename[64]; /* Constructed object filename */ + char base[64]; /* sba200/sba200e/pca200e basename */ + int ext = 0; /* 0 == bin 1 == objd */ + struct stat sbuf; /* Used to find if .bin or .objd */ + extern char *optarg; + + progname = (char *)basename(argv[0]); + comm_mode = strcmp ( progname, "fore_comm" ) == 0; + + while ( ( c = getopt ( argc, argv, "i:d:f:berv" ) ) != EOF ) + switch ( c ) { + case 'b': + binary++; + break; + case 'd': + dirname = (char *)strdup ( optarg ); + break; + case 'e': + endian++; + break; + case 'i': + devname = (char *)strdup ( optarg ); + break; + case 'f': + objfile = (char *)strdup ( optarg ); + break; + case 'v': + verbose++; + break; + case 'r': + reset++; + break; + case '?': + printf ( "usage: %s [-v] [-i intf] [-d dirname] [-f objfile]\n", argv[0] ); + exit ( 2 ); + } + + /* + * Unbuffer stdout + */ + setbuf ( stdout, NULL ); + + if ( ( fd = socket ( AF_ATM, SOCK_DGRAM, 0 ) ) < 0 ) + { + perror ( "Cannot create ATM socket" ); + exit ( 1 ); + } + /* + * Over allocate memory for returned data. This allows + * space for IOCTL reply info as well as config info. + */ + buf_len = 4 * sizeof(struct air_cfg_rsp); + if ( ( buf = (caddr_t)malloc(buf_len) ) == NULL ) + { + perror ( "Cannot allocate memory for reply" ); + exit ( 1 ); + } + /* + * Fill in request paramaters + */ + req.air_opcode = AIOCS_INF_CFG; + req.air_buf_addr = buf; + req.air_buf_len = buf_len; + + /* + * Copy interface name into ioctl request + */ + strcpy ( req.air_cfg_intf, devname ); + + /* + * Issue ioctl + */ + if ( ( ioctl ( fd, AIOCINFO, (caddr_t)&req ) ) ) { + perror ( "ioctl (AIOCSINFO)" ); + exit ( 1 ); + } + /* + * Reset buffer pointer + */ + req.air_buf_addr = buf; + + /* + * Close socket + */ + close ( fd ); + + /* + * Loop through all attached adapters + */ + for (; req.air_buf_len >= sizeof(struct air_cfg_rsp); + buf += sizeof(struct air_cfg_rsp), + req.air_buf_len -= sizeof(struct air_cfg_rsp)) { + + /* + * Point to vendor info + */ + air = (struct air_cfg_rsp *)buf; + + if (air->acp_vendor == VENDOR_FORE ) + { + /* + * Create /dev name + */ + sprintf ( bus_dev, DEV_NAME, air->acp_busslot ); + + /* + * Setup signal handlers + */ + signal ( SIGINT, SIG_IGN ); + signal ( SIGQUIT, SIG_IGN ); + + /* + * If comm_mode, setup terminal for single char I/O + */ + if ( comm_mode ) { + tty = open ( "/dev/tty", O_RDWR ); + ioctl ( tty, TCGETA, &sgtty ); + sgtty.c_lflag &= ~( ICANON | ECHO ); + vmin = sgtty.c_cc[VMIN]; + vtime = sgtty.c_cc[VTIME]; + sgtty.c_cc[VMIN] = 0; + sgtty.c_cc[VTIME] = 0; + ioctl ( tty, TCSETA, &sgtty ); + } + + /* + * Open bus for memory access + */ + if ( ( fd = open ( bus_dev, O_RDWR ) ) < 0 ) + { + perror ( "open bus_dev" ); + fprintf(stderr, "%s download failed (%s)\n", + air->acp_intf, bus_dev); + continue; + } + + /* + * Map in the RAM memory to get access to the Uart + */ +#ifdef __FreeBSD__ /*XXX*/ + ram = (u_char *) mmap(0, PCA200E_MMAP_SIZE, +#else + ram = (u_char *) mmap(0, air->acp_ramsize, +#endif + PROT_READ | PROT_WRITE, MAP_SHARED, + fd, air->acp_ram); + if (ram == (u_char *)-1) { + perror ( "mmap ram" ); + fprintf(stderr, "%s download failed\n", + air->acp_intf); + (void) close(fd); + continue; + } + Mon = (Mon960 *)(ram + MON960_BASE); + Uart = (Mon960 *)&(Mon->mon_xmitmon); + + /* + * Determine endianess + */ + switch ( Mon->mon_bstat ) { + case BOOT_COLDSTART: + case BOOT_MONREADY: + case BOOT_FAILTEST: + case BOOT_RUNNING: + break; + + default: + switch (ntohl(Mon->mon_bstat)) { + case BOOT_COLDSTART: + case BOOT_MONREADY: + case BOOT_FAILTEST: + case BOOT_RUNNING: + endian++; + break; + + default: + fprintf(stderr, "%s unknown status\n", + air->acp_intf); + (void) close(fd); + continue; + } + break; + } + +#ifdef __FreeBSD__ + if (reset) { + u_int *hcr = (u_int *)(ram + PCA200E_HCR_OFFSET); + PCA200E_HCR_INIT(*hcr, PCA200E_RESET_BD); + delay(10000); + PCA200E_HCR_CLR(*hcr, PCA200E_RESET_BD); + delay(10000); + } +#endif + + if ( comm_mode ) { + static struct timeval timeout = { 0, 0 }; + int esc_seen = 0; + + /* + * We want to talk with the i960 monitor + */ + + /* + * Loop forever accepting characters + */ + for ( ; ; ) { + fd_set fdr; + int ns; + + /* + * Check for data from the terminal + */ + FD_ZERO ( &fdr ); + FD_SET ( fileno(stdin), &fdr ); + + if ( ( ns = select ( FD_SETSIZE, &fdr, NULL, NULL, + &timeout ) ) < 0 ) { + perror ( "select" ); + finish( -1 ); + } + + if ( ns ) { + int c; + int nr; + + nr = read ( fileno(stdin), &c, 1 ); + c &= 0xff; + if ( !esc_seen ) { + if ( c == 27 ) + esc_seen++; + else + xmit_byte ( c, 0 ); + } else { + if ( c == 27 ) + finish( -1 ); + else { + xmit_byte ( 27, 0 ); + esc_seen = 0; + } + xmit_byte ( c, 0 ); + } + } + + /* + * Check for data from the i960 + */ + if ( CP_READ(Uart->mon_xmithost) & UART_VALID ) { + c = getbyte(0); + putchar ( c ); + } + if ( strcmp ( line, "Mon960" ) == 0 ) + autobaud(); + + } + } else { + /* + * Make sure the driver is loaded and that the CP + * is ready for commands + */ + if ( CP_READ(Mon->mon_bstat) == BOOT_RUNNING ) + { + fprintf ( stderr, + "%s is up and running - no download allowed.\n", + air->acp_intf ); + (void) close(fd); + continue; + } + + if ( CP_READ(Mon->mon_bstat) != BOOT_MONREADY ) + { + fprintf ( stderr, + "%s is not ready for downloading.\n", + air->acp_intf ); + (void) close(fd); + continue; + } + + /* + * Indicate who we're downloading + */ + if ( verbose ) + printf ( "Downloading code for %s\n", + air->acp_intf ); + + /* + * Look for the i960 monitor message. + * We should see this after a board reset. + */ + while ( strncmp ( line, "Mon960", 6 ) != 0 && + strncmp ( line, "=>", 2 ) != 0 ) + getline( verbose ); /* Verbose */ + + /* + * Autobaud fakery + */ + if ( strncmp ( line, "Mon960", 6 ) == 0 ) { + xmit_to_i960 ( "\r\n\r\n\r\n\r\n", 8, 0 ); + delay ( 10000 ); + } + + /* + * Keep reading until we get a command prompt + */ + while ( strncmp ( line, "=>", 2 ) != 0 ) + getline( verbose ); /* Verbose */ + + /* + * Choose the correct microcode file based on the + * adapter type the card claims to be. + */ + switch ( air->acp_device ) + { + case DEV_FORE_SBA200: + sprintf ( base, "sba200" ); + break; + + case DEV_FORE_SBA200E: + sprintf ( base, "sba200e" ); + break; + + case DEV_FORE_PCA200E: + sprintf ( base, "pca200e" ); + break; + + default: + err = 1; + fprintf(stderr, "Unknown adapter type: %d\n", + air->acp_device ); + } + + sndfile = NULL; + + if ( objfile == NULL ) { + switch ( air->acp_device ) { + case DEV_FORE_SBA200: + case DEV_FORE_SBA200E: + sprintf ( filename, "%s.bin%d", base, + air->acp_bustype ); + if ( stat ( filename, &sbuf ) == -1 ) { + sprintf ( filename, "%s/%s.bin%d", + dirname, base, + air->acp_bustype ); + if ( stat ( filename, &sbuf ) == -1 ) { + ext = 1; + sprintf ( filename, "%s.objd%d", + base, air->acp_bustype ); + if ( stat(filename, &sbuf) == -1 ) { + sprintf ( filename, + "%s/%s.objd%d", dirname, + base, + air->acp_bustype ); + if ( stat ( filename, &sbuf ) != -1 ) + sndfile = filename; + } else + sndfile = filename; + } else + sndfile = filename; + } else + sndfile = filename; + break; + case DEV_FORE_PCA200E: + sprintf ( filename, "%s.bin", base ); + if ( stat ( filename, &sbuf ) == -1 ) { + sprintf ( filename, "%s/%s.bin", + dirname, base ); + if ( stat ( filename, &sbuf ) != -1 ) { + sndfile = filename; + } + } else + sndfile = filename; + break; + } + } else + sndfile = objfile; + + if ( ext && !binary ) + err = sendfile ( sndfile ); + else + err = sendbinfile ( sndfile, ram ); + + if ( err ) { + fprintf(stderr, "%s download failed\n", + air->acp_intf); + (void) close(fd); + continue; + } + + /* + * Download completed - wait around a while for + * the driver to initialize the adapter + */ + aap = (Aali *)(ram + CP_READ(Mon->mon_appl)); + for (i = 0; i < MAX_CHECK; i++, sleep(1)) { + u_long hb1, hb2; + + if (CP_READ(Mon->mon_bstat) != BOOT_RUNNING) + continue; + + hb1 = CP_READ(aap->aali_heartbeat); + delay(1); + hb2 = CP_READ(aap->aali_heartbeat); + if (hb1 < hb2) + break; + } + } + + close ( fd ); + } + } + + /* + * Exit + */ + exit (0); + +} + diff --git a/sbin/atm/ilmid/Makefile b/sbin/atm/ilmid/Makefile new file mode 100644 index 0000000..b7ed852 --- /dev/null +++ b/sbin/atm/ilmid/Makefile @@ -0,0 +1,36 @@ +# +# +# =================================== +# 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. +# +# @(#) $Id: Makefile,v 1.5 1998/07/10 16:01:58 jpt Exp $ +# +# + +PROG= ilmid +MAN8= ilmid.8 + +CFLAGS+= -I ${.CURDIR}/../../../sys +LDADD+= -latm + +.include <bsd.prog.mk> diff --git a/sbin/atm/ilmid/ilmid.8 b/sbin/atm/ilmid/ilmid.8 new file mode 100644 index 0000000..e837adb --- /dev/null +++ b/sbin/atm/ilmid/ilmid.8 @@ -0,0 +1,118 @@ +.\" +.\" =================================== +.\" 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. +.\" +.\" @(#) $Id:$ +.\" +.\" +.de EX \"Begin example +.ne 5 +.if n .sp 1 +.if t .sp .5 +.nf +.in +.5i +.. +.de EE +.fi +.in -.5i +.if n .sp 1 +.if t .sp .5 +.. +.TH ILMID 8 "1998-09-14" "HARP" +.SH NAME +ilmid \- Simple ILMI ATM address registration daemon +.SH SYNOPSIS +.B ilmid +[-d level] +[-f] +[-r] +.sp +.fi +.SH DESCRIPTION +.B ilmid +is a HARP ATM daemon that performs the ILMI ATM address registration +procedures with an ATM network switch. It is normally invoked at boot time +from the ATM startup script. +.fi +.PP +For each ATM interface with a UNI signalling manager attached, +.B ilmid +will open an ILMI PVC (VPI = 0, VCI = 16) and register the interface's +ATM address with the switch. As part of the address registration procedure, +the ATM switch will notify the endsystem (local host) of the +"network prefix" portion of the endsystem's ATM address and +.B ilmid +will notify the switch of the endsystem's "user part" of its address +(typically the interface card MAC address). +.fi +.SH OPTIONS +.TP +.B \-d level +Specify the debug level for optional protocol tracing. Messages are +written to /var/log/ilmid. +.TP +.B \-f +Causes +.B ilmid +to run in the foregroud. +.TP +.B \-r +Causes +.B ilmid +to issue a coldStart TRAP on all ATM interfaces it's able to open and exit. +.fi +.SH NOTES +.PP +This daemon does not fully conform to the ATM Forum ILMI specifications. +In particular, it +does not make any queries of the network side to ensure +that the ATM Address table is empty. +It also does not implement any +of the ATM Forum MIB that is specified as part of ILMI. +.fi +.PP +.B ilmid +will increment the debug level when it receives a SIGUSR1 signal and will +decrement the debug level when it receives a SIGUSR2 signal. +.SH "SEE ALSO" +.PP +The ATM Forum, \fIATM User-Network Interface, Version 3.1 (UNI 3.1) +Specification\fP for details on the ILMI protocols and address registration +procedures. +.fi +.SH BUGS +Please report any bugs to harp-bugs@magic.net. +.fi +.SH COPYRIGHT +Copyright (c) 1994-1998, Network Computing Services, Inc. +.fi +.SH AUTHORS +John Cavanaugh, Network Computing Services, Inc. +.br +Mike Spengler, Network Computing Services, Inc. +.br +Joseph Thomas, Network Computing Services, Inc. +.fi +.SH ACKNOWLEDGMENTS +This software was developed with the support of the +Defense Advanced Research Projects Agency (DARPA). diff --git a/sbin/atm/ilmid/ilmid.c b/sbin/atm/ilmid/ilmid.c new file mode 100644 index 0000000..e515a10 --- /dev/null +++ b/sbin/atm/ilmid/ilmid.c @@ -0,0 +1,2810 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: ilmid.c,v 1.9 1998/08/13 20:15:28 jpt Exp $ + * + */ + +/* + * User utilities + * -------------- + * + * Implement very minimal ILMI address registration. + * + * Implement very crude and basic support for "cracking" and + * "encoding" SNMP PDU's to support ILMI prefix and NSAP address + * registration. Code is not robust nor is it meant to provide any + * "real" SNMP support. Much of the code expects predetermined values + * and will fail if anything else is found. Much of the "encoding" is + * done with pre-computed PDU's. + * + * See "The Simple Book", Marshall T. Rose, particularly chapter 5, + * for ASN and BER information. + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: ilmid.c,v 1.9 1998/08/13 20:15:28 jpt Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#if (defined(BSD) && (BSD >= 199103)) +#include <err.h> +#endif + +#ifdef BSD +#if __FreeBSD_version < 300001 +#include <stdlib.h> +#ifdef sun +#include <unistd.h> +#endif /* sun */ +#else +#include <unistd.h> +#endif /* __FreeBSD_version >= 300001 */ +#endif /* BSD */ + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> +#include <sys/errno.h> +#include <string.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <syslog.h> +#include <sys/socket.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_sigmgr.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <dev/hea/eni_stats.h> +#include <dev/hfa/fore_aali.h> +#include <dev/hfa/fore_slave.h> +#include <dev/hfa/fore_stats.h> +#include <netatm/uni/unisig_var.h> + +#define MAX_LEN 9180 + +#define MAX_UNITS 8 + +/* + * Time to sleep between loops + */ +#define SLEEP_TIME 10 +/* + * Time to pass between sending coldStart TRAPs + */ +#define TRAP_TIME 5 + +/* + * Define some ASN types + */ +#define ASN_INTEGER 0x02 +#define ASN_OCTET 0x04 +#define ASN_OBJID 0x06 +#define ASN_SEQUENCE 0x30 +#define ASN_IPADDR 0x40 +#define ASN_TIMESTAMP 0x43 + +/* + * Define SNMP PDU types + */ +#define PDU_TYPE_GET 0xA0 +#define PDU_TYPE_GETNEXT 0xA1 +#define PDU_TYPE_GETRESP 0xA2 +#define PDU_TYPE_SET 0xA3 +#define PDU_TYPE_TRAP 0xA4 + +/* + * Every SNMP PDU has the first four fields of this header. The only type + * which doesn't have the last three fields is the TRAP type. + */ +struct snmp_header { + int pdulen; + int version; + char community[64]; + int pdutype; + int reqid; + int error; + int erridx; +}; +typedef struct snmp_header Snmp_Header; + +/* + * Define our internal representation of an OBJECT IDENTIFIER + */ +struct objid { + int oid[128]; +}; +typedef struct objid Objid; + +/* + * Define some OBJET IDENTIFIERS that we'll try to reply to: + * + * sysUpTime: number of time ticks since this deamon came up + * netpfx_oid: network prefix table + * unitype: is this a PRIVATE or PUBLIC network link + * univer: which version of UNI are we running + * devtype: is this a USER or NODE ATM device + * setprefix: used when the switch wants to tell us its NSAP prefix + * foresiggrp: FORE specific Objid we see alot of (being connected to FORE + * switches...) + */ +Objid sysObjId = { 8, 43, 6, 1, 2, 1, 1, 2, 0 }; +Objid sysUpTime = { 8, 43, 6, 1, 2, 1, 1, 3, 0 }; +Objid foresiggrp = { 18, 43, 6, 1, 4, 1, 326, 2, 2, 2, 1, 6, 2, 1, 1, 1, 20, 0, 0 }; +Objid portidx = { 12, 43, 6, 1, 4, 1, 353, 2, 1, 1, 1, 1, 0 }; +Objid myipnm = { 10, 43, 6, 1, 4, 1, 353, 2, 1, 2, 0 }; +Objid layeridx = { 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 1, 0 }; +Objid maxvcc = { 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 3, 0 }; +Objid unitype = { 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 8, 0 }; +Objid univer = { 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 9, 0 }; +Objid devtype = { 12, 43, 6, 1, 4, 1, 353, 2, 2, 1, 1, 10, 0 }; +Objid netpfx_oid = { 9, 43, 6, 1, 4, 1, 353, 2, 7, 1 }; +Objid setprefix = { 12, 43, 6, 1, 4, 1, 353, 2, 7, 1, 1, 3, 0 }; +/* + * (Partialy) pre-encoded SNMP responses + */ + +/* + * sysObjId reply + */ +u_char sysObjId_Resp[] = { + 54, /* <--- len */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x32, /* <--- len */ + 0x02, 0x01, 0x00, /* (Version - 1) */ + 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */ + PDU_TYPE_GETRESP, /* GET Response */ + 0x27, /* <--- len */ + 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* <--- request id */ + 0x02, 0x01, 0x00, /* Error Status */ + 0x02, 0x01, 0x00, /* Error Index */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x17, /* <--- len */ + 0x82, 0x00, 0x14, /* <--- len */ + 0x06, 0x08, /* Objid: 1.3.6.1.4.1.1.2.0 */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x01, 0x02, 0x00, + 0x06, 0x08, /* Objid: 1.3.6.1.4.1.9999.1 */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0xce, 0x0f, 0x01 +}; + +/* + * sysUpTime: reply to a sysUpTime GET request + */ +u_char sysUpTime_Resp[] = { + 45, /* <--- len */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x29, /* <--- len */ + 0x02, 0x01, 0x00, /* (Version - 1) */ + 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community - ILMI */ + PDU_TYPE_GETRESP, /* GET Response */ + 0x1e, /* <--- len */ + 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* <--- request id */ + 0x02, 0x01, 0x00, /* Error Status */ + 0x02, 0x01, 0x00, /* Error Index */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x0E, /* <--- len */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x0A, /* <--- len */ + /* Objid: .1.3.6.1.2.1.1.3.0 */ + 0x06, 0x08, 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x03, 0x00, + /* <--- uptime */ +}; + +/* + * coldStart TRAP to start the ILMI protocol + */ +u_char coldStart_Trap[] = { + 60, + 0x30, /* Sequence of */ + 0x82, 0x00, 0x38, /* <--- len */ + 0x02, 0x01, 0x00, /* (Version - 1) */ + 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */ + PDU_TYPE_TRAP, /* TRAP */ + 0x2d, /* <--- len */ + 0x06, 0x08, /* Objid: .1.3.6.1.4.1.3.1.1 */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x03, 0x01, 0x01, + 0x40, 0x04, 0x00, 0x00, 0x00, 0x00, /* IP address - 0.0.0.0 */ + 0x02, 0x01, 0x00, /* generic trap */ + 0x02, 0x01, 0x00, /* specific trap */ + 0x43, 0x01, 0x00, /* Time ticks - 0 */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x10, /* <--- len */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x0c, /* <-- len */ + 0x06, 0x08, /* Objid: 1.3.6.1.2.1.1.3.0 */ + 0x2b, 0x06, 0x01, 0x02, 0x01, 0x01, 0x03, 0x00, + 0x05, 0x00 /* Null */ +}; + +u_char GetNext_Resp[] = { + 49, + 0x30, /* Sequence of */ + 0x82, 0x00, 0x2d, /* <--- len */ + 0x02, 0x01, 0x00, /* (Version - 1) */ + 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */ + PDU_TYPE_GETRESP, /* PDU_TYPE_GETRESP */ + 0x22, /* <--- len */ + 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* Request ID */ + 0x02, 0x01, 0x02, /* Error Status */ + 0x02, 0x01, 0x01, /* Error Index */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x12, /* <--- len */ + 0x30, /* Seqence of */ + 0x82, 0x00, 0x0e, /* <--- len */ + 0x06, 0x0a, /* Objid: .1.3.6.4.1.353.2.7.1 */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x61, 0x02, 0x07, 0x01, + 0x05, 0x00 /* Get response: NULL */ +}; + +/* + * Reply to GET myIpNm + */ +u_char MyIpNm_Resp[] = { + 54, + 0x30, /* Sequence of */ + 0x82, 0x00, 0x32, /* <--- len */ + 0x02, 0x01, 0x00, /* (Version - 1) */ + 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */ + PDU_TYPE_GETRESP, /* PDU_TYPE_GETRESP */ + 0x27, /* <--- len */ + 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* Request ID */ + 0x02, 0x01, 0x00, /* Error Status */ + 0x02, 0x01, 0x00, /* Error Index */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x17, /* <--- len */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x13, /* <--- len */ + /* Objid: .1.3.6.1.4.1.353.2.1.2.1 */ + 0x06, 0x0B, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x61, 0x02, + 0x01, 0x02, 0x01, + 0x40, 0x04, 0x00, 0x00, 0x00, 0x00 /* IP address */ +}; + +/* + * Reply to GET portIndex - we're always 1 + unit number + */ +u_char PortIndex_Resp[] = { + 53, + 0x30, /* Sequence of */ + 0x82, 0x00, 0x31, /* <-- len */ + 0x02, 0x01, 0x00, /* (Version - 1) */ + 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */ + PDU_TYPE_GETRESP, + 0x26, /* <-- len */ + 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* Request ID */ + 0x02, 0x01, 0x00, /* Error Status */ + 0x02, 0x01, 0x00, /* Error Index */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x16, /* <--- len */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x12, /* <--- len */ + /* Objid: .1.3.6.1.4.1.353.2.1.1.1.1.x */ + 0x06, 0x0d, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x61, 0x02, + 0x01, 0x01, 0x01, 0x01, 0x00, + 0x02, 0x01, 0x00, /* Value */ +}; + +/* + * Reply to GET MaxVcc + */ +u_char maxVCC_Resp[] = { + 52, /* <--- len */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x30, /* <--- len */ + 0x02, 0x01, 0x01, /* (Version - 1) */ + 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */ + PDU_TYPE_GETRESP, /* GET Response */ + 0x25, /* <--- len */ + 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* <--- request id */ + 0x02, 0x01, 0x00, /* Error Status */ + 0x02, 0x01, 0x00, /* Error Index */ + 0x30, /* Sequence of */ + 0x82, 0x16, /* <--- len */ + 0x30, /* Sequence of */ + 0x82, 0x13, /* <--- len */ + 0x06, 0x0d, /* Objid: 1.3.6.1.4.1.353.2.2.1.1.3.0 */ + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x61, 0x02, + 0x02, 0x01, 0x01, 0x03, 0x00, + 0x02, 0x02, 0x04, 0x00 /* Value = 1024 */ +}; + +/* + * Reply to GET uniType - we only support PRIVATE + */ +u_char UniType_Resp[] = { + 53, + 0x30, /* Sequence of */ + 0x82, 0x00, 0x31, /* <--- len */ + 0x02, 0x01, 0x00, /* (Version - 1) */ + 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */ + PDU_TYPE_GETRESP, /* PDU_TYPE_GETRESP */ + 0x26, /* <--- len */ + 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* Request ID */ + 0x02, 0x01, 0x00, /* Error Status */ + 0x02, 0x01, 0x00, /* Error Index */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x16, /* <--- len */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x12, /* <--- len */ + /* Objid: .1.3.6.1.4.1.353.2.2.1.1.8.0 */ + 0x06, 0x0d, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x61, 0x02, 0x02, + 0x01, 0x01, 0x08, 0x00, + 0x02, 0x01, 0x02 /* Get response: Integer */ + /* = UNITYPE_PRIVATE (2) */ +}; + +#define UNIVER_UNI30 2 +#define UNIVER_UNI31 3 +#define UNIVER_UNI40 4 + +/* + * Reply to GET uniVer + */ +u_char UniVer_Resp[] = { + 53, + 0x30, /* Sequence of */ + 0x82, 0x00, 0x31, /* <--- len */ + 0x02, 0x01, 0x00, /* (Version - 1) */ + 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */ + PDU_TYPE_GETRESP, /* PDU_TYPE_GETRESP */ + 0x26, /* <--- len */ + 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* Request ID */ + 0x02, 0x01, 0x00, /* Error Status */ + 0x02, 0x01, 0x00, /* Error Index */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x16, /* <--- len */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x12, /* <--- len */ + /* Objid: .1.3.6.1.4.1.353.2.2.1.1.9.0 */ + 0x06, 0x0d, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x61, 0x02, 0x02, + 0x01, 0x01, 0x09, 0x00, + 0x02, 0x01, 0x02 /* Get response: Integer */ + /* = UNIVER_UNI30 (2) */ +}; + +/* + * Reply to GET devType - we're a host therefore we're type USER + */ +u_char DevType_Resp[] = { + 53, + 0x30, /* Sequence of */ + 0x82, 0x00, 0x31, /* <--- len */ + 0x02, 0x01, 0x00, /* (Version -1) */ + 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */ + PDU_TYPE_GETRESP, /* PDU_TYPE_GETRESP */ + 0x26, /* <--- len */ + 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* Request ID */ + 0x02, 0x01, 0x00, /* Error Status */ + 0x02, 0x01, 0x00, /* Error Index */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x16, /* <--- len */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x12, /* <--- len */ + /* Objid: .1.3.6.1.4.1.353.2.2.1.1.10.0 */ + 0x06, 0x0d, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x61, 0x02, 0x02, + 0x01, 0x01, 0x0a, 0x00, + 0x02, 0x01, 0x01 /* Get response: Integer */ + /* = DEVTYPE_USER (1) */ +}; + +/* + * Reply to GET foreSigGroup.* with noSuchError + */ +u_char NoSuchFore_Resp[] = { + 85, + 0x30, /* Sequence of */ + 0x82, 0x00, 0x51, /* <--- len */ + 0x02, 0x01, 0x00, /* (Version - 1) */ + 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */ + PDU_TYPE_GETRESP, /* PDU_TYPE_GETRESP */ + 0x46, /* <--- len */ + 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* Request ID */ + 0x02, 0x01, 0x02, /* Error Status: noSuch (2) */ + 0x02, 0x01, 0x01, /* Error Index */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x36, /* <--- len */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x17, /* <--- len */ + /* Objid: .1.3.6.1.5.1.326.2.2.2.1.6.2.1.1.1.20.0.0 */ + 0x06, 0x13, + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x46, + 0x02, 0x02, 0x02, 0x01, 0x06, 0x02, 0x01, 0x01, + 0x01, 0x14, 0x00, 0x00, + 0x05, 0x00, /* NULL */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x17, /* <--- len */ + /* Objid: .1.3.6.1.5.1.326.2.2.2.1.6.2.1.1.1.21.0.0 */ + 0x06, 0x13, + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x46, + 0x02, 0x02, 0x02, 0x01, 0x06, 0x02, 0x01, 0x01, + 0x01, 0x15, 0x00, 0x00, + 0x05, 0x00 /* NULL */ +}; + +u_char NetPrefix_Resp[] = { + 50, + 0x30, /* Sequence of */ + 0x82, 0x00, 0x00, /* <--- len */ + 0x02, 0x01, 0x00, /* (Version - 1) */ + 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, /* Community: ILMI */ + PDU_TYPE_SET, /* PDU_TYPE_SET */ + 0x00, /* <--- len */ + 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, /* Request ID */ + 0x02, 0x01, 0x00, + 0x02, 0x01, 0x00, + 0x30, /* Sequence of */ + 0x82, 0x00, 0x00, /* <--- len */ + 0x30, /* Sequence of */ + 0x82, 0x00, 0x00, /* <--- len */ + /* Objid: .1.3.6.1.4.1.353.2.6.1.1.3.0. */ + 0x06, 0x00, + 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x61, 0x02, + 0x06, 0x01, 0x01, 0x03, 0x00 + /* Remainder of Objid plus SET value INTEGER =1 */ +}; + +/* + * Our (incrementing) Request ID + */ +int Req_ID = 0; + +/* + * Temporary buffer for building response packets. Should help ensure + * that we aren't accidently overwriting some other memory. + */ +u_char Resp_Buf[1024]; + +/* + * Copy the reponse into a buffer we can modify without + * changing the original... + */ +#define COPY_RESP(resp) \ + UM_COPY ( (resp), Resp_Buf, (resp)[0] + 1 ) + +/* + * TRAP generic trap types + */ +char *Traps[] = { "coldStart", "warmStart", "linkDown", "linkUp", + "authenticationFailure", "egpNeighborLoss", + "enterpriseSpecific" }; + + +int NUnits; +/* + * Time last coldStart trap was sent to this unit + */ +time_t last_trap[MAX_UNITS]; +/* + * fd for units still awiting coldStart TRAP from network side + */ +int trap_fd[MAX_UNITS]; +/* + * fd for units which have seen a coldStart TRAP and are now exchaning SNMP requests + */ +int ilmi_fd[MAX_UNITS]; +/* + * Local copy for HARP physical configuration information + */ +struct air_cfg_rsp Cfg[MAX_UNITS + 1]; +/* + * Local copy for HARP interface configuration information + */ +struct air_int_rsp Intf[MAX_UNITS + 1]; + +/* + * When this daemon started + */ +struct timeval starttime; + +int Debug_Level = 0; + +char *progname; +char hostname[80]; + + /* File to write debug messages to */ +#define LOG_FILE "/var/log/ilmid" +FILE *Log; /* File descriptor for log messages */ + +extern int errno; + +#ifdef sun +extern char *optarg; +extern int optind, opterr; +extern int getopt __P((int, char **, char *)); +#endif /* sun */ + +void set_reqid __P ( ( u_char *, int ) ); +void Increment_DL __P ( ( int ) ); +void Decrement_DL __P ( ( int ) ); + +static char *Months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; + +/* + * Write a syslog() style timestamp + * + * Write a syslog() style timestamp with month, day, time and hostname + * to the log file. + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +write_timestamp() +{ + time_t clock; + struct tm *tm; + + clock = time ( (time_t)NULL ); + tm = localtime ( &clock ); + + if ( Log ) + fprintf ( Log, "%.3s %2d %.2d:%.2d:%.2d %s: ", + Months[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min, + tm->tm_sec, hostname ); + + return; + +} + +/* + * Utility to pretty print buffer as hex dumps + * + * Arguments: + * bp - buffer pointer + * len - length to pretty print + * + * Returns: + * none + * + */ +void +hexdump ( bp, len ) + u_char *bp; + int len; +{ + int i, j; + + /* + * Print as 4 groups of four bytes. Each byte seperated + * by space, each block of four seperated, and two blocks` + * of eight also seperated. + */ + for ( i = 0; i < len; i += 16 ) { + if ( Log ) + write_timestamp(); + for ( j = 0; j < 4 && j + i < len; j++ ) + if ( Log ) + fprintf ( Log, "%.2x ", *bp++ ); + if ( Log ) + fprintf ( Log, " " ); + for ( ; j < 8 && j + i < len; j++ ) + if ( Log ) + fprintf ( Log, "%.2x ", *bp++ ); + if ( Log ) + fprintf ( Log, " " ); + for ( ; j < 12 && j + i < len; j++ ) + if ( Log ) + fprintf ( Log, "%.2x ", *bp++ ); + if ( Log ) + fprintf ( Log, " " ); + for ( ; j < 16 && j + i < len; j++ ) + if ( Log ) + fprintf ( Log, "%.2x ", *bp++ ); + if ( Log ) + fprintf ( Log, "\n" ); + } + + return; + +} + +/* + * Get lengths from PDU encodings + * + * Lengths are sometimes encoded as a single byte if the length + * is less the 127 but are more commonly encoded as one byte with + * the high bit set and the lower seven bits indicating the nuber + * of bytes which make up the length value. Trailing data is (to my + * knowledge) not 7-bit encoded. + * + * Arguments: + * bufp - pointer to buffer pointer + * + * Returns: + * bufp - updated buffer pointer + * <len> - decoded length + * + */ +int +asn_get_pdu_len ( bufp ) + u_char **bufp; +{ + u_char *bp = *bufp; + int len = 0; + int i, b; + + b = *bp++; + if ( b & 0x80 ) { + for ( i = 0; i < (b & ~0x80); i++ ) + len = len * 256 + *bp++; + } else + len = b; + + *bufp = bp; + return ( len ); +} + +/* + * Get an 7-bit encoded value. + * + * Get a value which is represented using a 7-bit encoding. The last + * byte in the stream has the high-bit clear. + * + * Arguments: + * bufp - pointer to the buffer pointer + * len - pointer to the buffer length + * + * Returns: + * bufp - updated buffer pointer + * len - updated buffer length + * <val> - value encoding represented + * + */ +int +asn_get_encoded ( bufp, len ) + u_char **bufp; + int *len; +{ + u_char *bp = *bufp; + int val = 0; + int l = *len; + + /* + * Keep going while high bit is set + */ + do { + /* + * Each byte can represent 7 bits + */ + val = ( val << 7 ) + ( *bp & ~0x80 ); + l--; + } while ( *bp++ & 0x80 ); + + *bufp = bp; /* update buffer pointer */ + *len = l; /* update buffer length */ + + return ( val ); +} + +/* + * Get a BER encoded integer + * + * Intergers are encoded as one byte length followed by <length> data bytes + * + * Arguments: + * bufp - pointer to the buffer pointer + * + * Returns: + * bufp - updated buffer pointer + * <val> - value of encoded integer + * + */ +int +asn_get_int ( bufp ) + u_char **bufp; +{ + int i; + int len; + int v = 0; + u_char *bp = *bufp; + + len = *bp++; + for ( i = 0; i < len; i++ ) { + v = (v * 256) + *bp++; + } + *bufp = bp; + return ( v ); +} + +/* + * Utility to print a object identifier + * + * Arguments: + * objid - pointer to objid representation + * + * Returns: + * none + * + */ +void +print_objid ( objid ) + Objid *objid; +{ + int i; + + /* + * First oid coded as 40 * X + Y + */ + if ( Log ) { + write_timestamp(); + fprintf ( Log, ".%d.%d", objid->oid[1] / 40, + objid->oid[1] % 40 ); + } + for ( i = 2; i <= objid->oid[0]; i++ ) + if ( Log ) + fprintf ( Log, ".%d", objid->oid[i] ); + if ( Log ) + fprintf ( Log, "\n" ); + + return; +} + +/* + * Get Object Identifier + * + * Arguments: + * bufp - pointer to buffer pointer + * objid - pointer to objid buffer + * + * Returns: + * bufp - updated buffer pointer + * objid - internal representation of encoded objid + * + */ +void +asn_get_objid ( bufp, objid ) + u_char **bufp; + Objid *objid; +{ + int len; + u_char *bp = *bufp; + int *ip = (int *)objid + 1; /* First byte will contain length */ + int oidlen = 0; + + len = *bp++; + while ( len ) { + *ip++ = asn_get_encoded ( &bp, &len ); + oidlen++; + } + objid->oid[0] = oidlen; + *bufp = bp; + + if ( Debug_Level > 1 ) + print_objid ( objid ); + + return; +} + +/* + * Get OCTET STRING + * + * Octet strings are encoded as a 7-bit encoded length followed by <len> + * data bytes; + * + * Arguments: + * bufp - pointer to buffer pointer + * octet - pointer to octet buffer + * + * Returns: + * bufp - updated buffer pointer + * octet - encoded Octet String + * + */ +void +asn_get_octet ( bufp, octet ) + u_char **bufp; + char *octet; +{ + u_char *bp = *bufp; + int i = 0; + int len = 0; + + /* + * &i is really a dummy value here as we don't keep track + * of the ongoing buffer length + */ + len = asn_get_encoded ( &bp, &i ); + + for ( i = 0; i < len; i++ ) + *octet++ = *bp++; + + *bufp = bp; + + return; + +} + +/* + * Utility to print SNMP PDU header information + * + * Arguments: + * Hdr - pointer to internal SNMP header structure + * + * Returns: + * none + * + */ +void +print_header ( Hdr ) + Snmp_Header *Hdr; +{ + if ( Log ) { + write_timestamp(); + fprintf ( Log, + "Pdu len: %d Version: %d Community: \"%s\" Pdu Type: 0x%x\n", + Hdr->pdulen, Hdr->version + 1, Hdr->community, + Hdr->pdutype ); + } + if ( Hdr->pdutype != PDU_TYPE_TRAP && Log ) + fprintf ( Log, "\tReq Id: 0x%x Error: %d Error Index: %d\n", + Hdr->reqid, Hdr->error, Hdr->erridx ); + + return; + +} + +/* + * Crack the SNMP header + * + * Pull the PDU length, SNMP version, SNMP community and PDU type. + * If present, also pull out the Request ID, Error status, and Error + * index values. + * + * Arguments: + * bufp - pointer to buffer pointer + * + * Returns: + * bufp - updated buffer pointer + * - generated SNMP header + * + */ +Snmp_Header * +asn_get_header ( bufp ) + u_char **bufp; +{ + Snmp_Header *h; + u_char *bp = *bufp; + + /* + * Allocate memory to hold the SNMP header + */ + if ( ( h = (Snmp_Header *)UM_ALLOC(sizeof(Snmp_Header)) ) == NULL ) + return ( (Snmp_Header *)NULL ); + + /* + * PDU has to start as SEQUENCE OF + */ + if ( *bp++ != ASN_SEQUENCE ) /* Class == Universial, f == 1, tag == SEQUENCE */ + return ( (Snmp_Header *)NULL ); + + /* + * Get the length of remaining PDU data + */ + h->pdulen = asn_get_pdu_len ( &bp ); + + /* + * We expect to find an integer encoding Version-1 + */ + if ( *bp++ != ASN_INTEGER ) { + return ( (Snmp_Header *)NULL ); + } + h->version = asn_get_int ( &bp ); + + /* + * After the version, we need the community name + */ + if ( *bp++ != ASN_OCTET ) { + return ( (Snmp_Header *)NULL ); + } + UM_ZERO ( h->community, sizeof ( h->community ) ); + asn_get_octet ( &bp, h->community ); + + /* + * Single byte PDU type + */ + h->pdutype = *bp++; + + /* + * If this isn't a TRAP PDU, then look for the rest of the header + */ + if ( h->pdutype != PDU_TYPE_TRAP ) { /* TRAP uses different format */ + + bp++; /* Skip over data len */ + + /* Request ID */ + if ( *bp++ != ASN_INTEGER ) { + return ( (Snmp_Header *)NULL ); + } + h->reqid = asn_get_int ( &bp ); + + /* Error Status */ + if ( *bp++ != ASN_INTEGER ) { + return ( (Snmp_Header *)NULL ); + } + h->error = asn_get_int ( &bp ); + + /* Error Index */ + if ( *bp++ != ASN_INTEGER ) { + return ( (Snmp_Header *)NULL ); + } + h->erridx = asn_get_int ( &bp ); + + } + + *bufp = bp; + + if ( Debug_Level > 2 ) + print_header ( h ); + + return ( h ); + +} + +/* + * Compare to internal OID representations + * + * Arguments: + * oid1 - Internal Object Identifier + * oid2 - Internal Object Identifier + * + * Returns: + * 0 - Objid's match + * 1 - Objid's don't match + * + */ +int +oid_cmp ( oid1, oid2 ) + Objid *oid1, *oid2; +{ + int i; + + /* + * Compare lengths + */ + if ( !(oid1->oid[0] == oid2->oid[0]) ) + /* Different lengths */ + return ( 1 ); + + /* + * value by value compare + */ + for ( i = 1; i <= oid1->oid[0]; i++ ) { + if ( !(oid1->oid[i] == oid2->oid[i]) ) + /* values don't match */ + return ( 1 ); + } + + /* Objid's are identical */ + return ( 0 ); +} + +/* + * Encode a timeval as the number of time ticks + * + * Time ticks are the number of 100th's of a second since some event. + * For sysUpTime, this is the time ticks since the application started, + * not since the host came up. We only support encoding ticks since we + * started running (what we are calling 'starttime'). + * + * Arguments: + * bufp - pointer to buffer pointer + * + * Returns: + * bufp - updated buffper pointer + * len - number of bytes to encode time ticks value + * - ticks since 'starttime' encoded in buffer + * + */ +int +asn_encode_ticks ( bufp, ret ) + u_char **bufp; + int *ret; +{ + struct timeval timenow; + struct timeval timediff; + u_char *bp = *bufp; + int len, ticks; + + (void) gettimeofday ( &timenow, NULL ); + /* + * Adjust for subtraction + */ + timenow.tv_sec--; + timenow.tv_usec += 1000000; + + /* + * Compute time since 'starttime' + */ + timediff.tv_sec = timenow.tv_sec - starttime.tv_sec; + timediff.tv_usec = timenow.tv_usec - starttime.tv_usec; + + /* + * Adjust difference timeval + */ + if ( timediff.tv_usec > 1000000 ) { + timediff.tv_usec -= 1000000; + timediff.tv_sec++; + } + + /* + * Compute 100th's of second in diff time structure + */ + *ret = ticks = (timediff.tv_sec * 100) + (timediff.tv_usec / 10000); + + /* + * The rest of this is just plain gross. I'm sure there + * are better ways to do this... + */ + + /* Compute time ticks length */ + if ( ticks < 0xFF ) + len = 1; + else if ( ticks < 0xFFFF ) + len = 2; + else if ( ticks < 0xFFFFFF ) + len = 3; + else + len = 4; + + /* + * Encode time ticks + */ + *bp++ = ASN_TIMESTAMP; /* Time Ticks */ + *bp++ = len; /* length of value */ + + /* there's always a better way but this is quick and dirty... */ + if ( ticks > 0xFFFFFF ) { + *bp++ = ( ticks & 0xFF000000 ) >> 24; + ticks &= 0xFFFFFF; + } + if ( ticks > 0xFFFF ) { + *bp++ = ( ticks & 0xFF0000 ) >> 16; + ticks &= 0xFFFF; + } + if ( ticks > 0xFF ) { + *bp++ = ( ticks & 0xFF00 ) >> 8; + ticks &= 0xFF; + } + *bp++ = ticks; + + *bufp = bp; + return ( len + 2 ); +} + +/* + * Send back up sysUpTime response + * + * Arguments: + * sd - socket descriptor to send reply on + * reqid - original GET request id + * + * Returns: + * none - response sent + * + */ +void +send_uptime_resp ( sd, reqid ) + int sd; + int reqid; +{ + int len; + short *sp; + u_long *ip; + u_char *bp; + short val; + int ticks; + + COPY_RESP ( sysUpTime_Resp ); + + bp = (u_char *)&Resp_Buf[Resp_Buf[0]+1]; + len = asn_encode_ticks ( &bp, &ticks ); + + /* + * Adjust overall length + */ + bp = (u_char *)&Resp_Buf[0]; + *bp += len; + + /* + * Adjust sequence lengths - works because this is my + * PDU and I know all the variable lengths are fixed (ie. + * reqid is always 4 byte encoded). + */ +#ifndef sun + sp = (short *)&Resp_Buf[3]; + val = ntohs ( *sp ); + *sp = htons ( val + len ); + Resp_Buf[15] += len; + sp = (u_short *)&Resp_Buf[30]; + val = ntohs ( *sp ); + *sp = htons ( val + len ); + sp = (u_short *)&Resp_Buf[34]; + val = ntohs ( *sp ); + *sp = htons ( val + len ); +#else + /* Sun SPARCs have alignment requirements */ + Resp_Buf[4] += len; + Resp_Buf[15] += len; + Resp_Buf[31] += len; + Resp_Buf[35] += len; +#endif /* sun */ + + /* + * Store the original request ID in the response + */ + set_reqid ( Resp_Buf, reqid ); +#ifdef notdef +#ifndef sun + ip = (u_long *)&Resp_Buf[18]; + *ip = htonl ( reqid ); +#else + /* Sun SPARCs have alignment requirements */ + UM_COPY ( (caddr_t)&reqid, (caddr_t)&Resp_Buf[18], sizeof(reqid) ); +#endif /* sun */ +#endif + + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "\tSend sysUpTime: %d\n", ticks ); + } + + if ( Debug_Level > 4 && Log ) { + write_timestamp(); + fprintf ( Log, "\n===== Sent %d bytes =====\n", Resp_Buf[0] ); + hexdump ( (u_char *)&Resp_Buf[1], Resp_Buf[0] ); + } + /* + * Send response + */ + write ( sd, (caddr_t)&Resp_Buf[1], Resp_Buf[0] ); + + return; + +} + +/* + * Set Request ID in PDU + * + * Arguments: + * resp - Response PDU buffer + * reqid - request id value + * + * Returns: + * none - request id may/may not be set + * + */ +void +set_reqid ( resp, reqid ) + u_char *resp; + int reqid; +{ + u_char *bp = (u_char *)&resp[18]; + union { + int i; + u_char c[4]; + } u; + +#ifndef sun + u.i = htonl(reqid); +#else + u.i = reqid; +#endif /* !sun */ + + /* + * Replace the current Request ID with the supplied value + */ + UM_COPY ( (caddr_t)&u.c[4-resp[17]], bp, resp[17] ); + + return; + +} + +/* + * Send a generic response packet + * + * Arguments: + * sd - socket to send the reply on + * reqid - original request ID from GET PDU + * resp - pointer to the response to send + * + * Returns: + * none - response sent + * + */ +void +send_resp ( sd, reqid, resp ) + int sd; + int reqid; + u_char *resp; +{ + + set_reqid ( resp, reqid ); + + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "===== Sent %d bytes =====\n", resp[0] ); + hexdump ( (u_char *)&resp[1], resp[0] ); + } + write ( sd, (caddr_t)&resp[1], resp[0] ); + + return; +} + +/* + * Initialize information on what physical adapters HARP knows about + * + * Query the HARP subsystem about configuration and physical interface + * information for any currently registered ATM adapters. Store the information + * as arrays for easier indexing by SNMP port/index numbers. + * + * Arguments: + * none + * + * Returns: + * none Information from HARP available + * + */ +void +init_ilmi() +{ + struct air_cfg_rsp *cfg_info = NULL; + struct air_intf_rsp *intf_info = NULL; + int buf_len; + + /* + * Get configuration info - what's available with 'atm sh config' + */ + buf_len = get_cfg_info ( NULL, &cfg_info ); + /* + * If error occurred, clear out everything + */ + if ( buf_len <= 0 ) { + UM_ZERO ( Cfg, sizeof(Cfg) ); + UM_ZERO ( Intf, sizeof(Intf) ); + NUnits = 0; + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "NUnits: %d\n", NUnits ); + } + return; + } + + /* + * Move to local storage + */ + UM_COPY ( cfg_info, (caddr_t)Cfg, buf_len ); + /* + * Compute how many units information was returned for + */ + NUnits = buf_len / sizeof(struct air_cfg_rsp); + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "NUnits: %d\n", NUnits ); + } + /* Housecleaning */ + free ( cfg_info ); + cfg_info = NULL; + /* + * Get the per interface information + */ + buf_len = get_intf_info ( NULL, &intf_info ); + /* + * If error occurred, clear out Intf info + */ + if ( buf_len <= 0 ) { + UM_ZERO ( Intf, sizeof(Intf) ); + return; + } + + /* + * Move to local storage + */ + UM_COPY ( intf_info, (caddr_t)Intf, buf_len ); + /* Housecleaning */ + free ( intf_info ); + intf_info = NULL; + + return; + +} + +/* + * Open a new SNMP session for ILMI + * + * Start by updating interface information, in particular, how many + * interfaces are in the system. While we'll try to open sessons on + * all interfaces, this deamon currently can only handle the first + * interface. + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +ilmi_open () +{ + struct sockaddr_atm satm; + struct t_atm_aal5 aal5; + struct t_atm_traffic traffic; + struct t_atm_bearer bearer; + struct t_atm_qos qos; + struct t_atm_app_name appname; + Atm_addr subaddr; + char buffer[MAX_LEN+1]; + char nifname[IFNAMSIZ]; + int optlen; + int unit = 0; + struct timer_elem *open_timer, + *state_timer; + u_char sig_proto; + + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "ilmi_open()\n" ); + } + init_ilmi(); + + for ( unit = 0; unit < NUnits; unit++ ) { + + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "Unit: %d Sig: %d Trap: %d Ilmi: %d\n", + unit, Intf[unit].anp_sig_proto, trap_fd[unit], + ilmi_fd[unit] ); + } + /* + * ILMI only makes sense for UNI signalling protocols + */ + sig_proto = Intf[unit].anp_sig_proto; + if ( sig_proto != ATM_SIG_UNI30 && sig_proto != ATM_SIG_UNI31 && + sig_proto != ATM_SIG_UNI40 ) + continue; + + /* + * If we're waiting for a coldStart TRAP, we'll be in trap_fd[], + * If we're processing ILMI, we'll be in ilmi_fd[], otherwise, + * this unit hasn't been opened yet. + */ + if ( trap_fd[unit] == -1 && ilmi_fd[unit] == -1 ) { + + trap_fd[unit] = socket ( AF_ATM, SOCK_SEQPACKET, ATM_PROTO_AAL5 ); + + if ( trap_fd[unit] < 0 ) { + perror ( "open" ); + continue; + } + + /* + * Set interface name. For now, we must have a netif to go on... + */ + if ( Intf[unit].anp_nif_cnt == 0 ) { + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "No nif on unit %d\n", unit ); + } + close ( trap_fd[unit] ); + trap_fd[unit] = -1; + ilmi_fd[unit] = -1; + continue; + } + sprintf ( nifname, "%s0\0", Intf[unit].anp_nif_pref ); + optlen = sizeof ( nifname ); + if ( setsockopt ( trap_fd[unit], T_ATM_SIGNALING, + T_ATM_NET_INTF, (caddr_t)nifname, optlen ) < 0 ) { + perror ( "setsockopt" ); + if ( Log ) { + write_timestamp(); + fprintf ( Log, + "Couldn't set interface name \"%s\"\n", + nifname ); + } + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "nifname: closing unit %d\n", unit ); + } + close ( trap_fd[unit] ); + trap_fd[unit] = -1; + ilmi_fd[unit] = -1; + continue; + } + + /* + * Set up destination SAP + */ + UM_ZERO ( (caddr_t) &satm, sizeof(satm) ); + satm.satm_family = AF_ATM; +#ifndef sun + satm.satm_len = sizeof(satm); +#endif /* sun */ + + satm.satm_addr.t_atm_sap_addr.SVE_tag_addr = T_ATM_PRESENT; + satm.satm_addr.t_atm_sap_addr.SVE_tag_selector = T_ATM_ABSENT; + satm.satm_addr.t_atm_sap_addr.address_format = T_ATM_PVC_ADDR; + satm.satm_addr.t_atm_sap_addr.address_length = sizeof(Atm_addr_pvc); + ATM_PVC_SET_VPI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address, + 0 ); + ATM_PVC_SET_VCI((Atm_addr_pvc *)satm.satm_addr.t_atm_sap_addr.address, + 16 ); + + satm.satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_PRESENT; + satm.satm_addr.t_atm_sap_layer2.ID_type = T_ATM_SIMPLE_ID; + satm.satm_addr.t_atm_sap_layer2.ID.simple_ID = T_ATM_BLLI2_I8802; + + satm.satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT; + + satm.satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT; + + /* + * Set up connection parameters + */ + aal5.forward_max_SDU_size = MAX_LEN; + aal5.backward_max_SDU_size = MAX_LEN; + aal5.SSCS_type = T_ATM_NULL; + optlen = sizeof(aal5); + if ( setsockopt ( trap_fd[unit], T_ATM_SIGNALING, T_ATM_AAL5, + (caddr_t) &aal5, optlen ) < 0 ) { + perror ( "setsockopt(aal5)" ); + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "aal5: closing unit %d\n", unit ); + } + close ( trap_fd[unit] ); + trap_fd[unit] = -1; + ilmi_fd[unit] = -1; + continue; + } + + traffic.forward.PCR_high_priority = T_ATM_ABSENT; + traffic.forward.PCR_all_traffic = 100000; + traffic.forward.SCR_high_priority = T_ATM_ABSENT; + traffic.forward.SCR_all_traffic = T_ATM_ABSENT; + traffic.forward.MBS_high_priority = T_ATM_ABSENT; + traffic.forward.MBS_all_traffic = T_ATM_ABSENT; + traffic.forward.tagging = T_NO; + traffic.backward.PCR_high_priority = T_ATM_ABSENT; + traffic.backward.PCR_all_traffic = 100000; + traffic.backward.SCR_high_priority = T_ATM_ABSENT; + traffic.backward.SCR_all_traffic = T_ATM_ABSENT; + traffic.backward.MBS_high_priority = T_ATM_ABSENT; + traffic.backward.MBS_all_traffic = T_ATM_ABSENT; + traffic.backward.tagging = T_NO; + traffic.best_effort = T_YES; + optlen = sizeof(traffic); + if (setsockopt(trap_fd[unit], T_ATM_SIGNALING, T_ATM_TRAFFIC, + (caddr_t)&traffic, optlen) < 0) { + perror("setsockopt(traffic)"); + } + bearer.bearer_class = T_ATM_CLASS_X; + bearer.traffic_type = T_ATM_NULL; + bearer.timing_requirements = T_ATM_NULL; + bearer.clipping_susceptibility = T_NO; + bearer.connection_configuration = T_ATM_1_TO_1; + optlen = sizeof(bearer); + if (setsockopt(trap_fd[unit], T_ATM_SIGNALING, T_ATM_BEARER_CAP, + (caddr_t)&bearer, optlen) < 0) { + perror("setsockopt(bearer)"); + } + + qos.coding_standard = T_ATM_NETWORK_CODING; + qos.forward.qos_class = T_ATM_QOS_CLASS_0; + qos.backward.qos_class = T_ATM_QOS_CLASS_0; + optlen = sizeof(qos); + if (setsockopt(trap_fd[unit], T_ATM_SIGNALING, T_ATM_QOS, (caddr_t)&qos, + optlen) < 0) { + perror("setsockopt(qos)"); + } + + subaddr.address_format = T_ATM_ABSENT; + subaddr.address_length = 0; + optlen = sizeof(subaddr); + if (setsockopt(trap_fd[unit], T_ATM_SIGNALING, T_ATM_DEST_SUB, + (caddr_t)&subaddr, optlen) < 0) { + perror("setsockopt(dest_sub)"); + } + + strncpy(appname.app_name, "ILMI", T_ATM_APP_NAME_LEN); + optlen = sizeof(appname); + if (setsockopt(trap_fd[unit], T_ATM_SIGNALING, T_ATM_APP_NAME, + (caddr_t)&appname, optlen) < 0) { + perror("setsockopt(appname)"); + } + + /* + * Now try to connect to destination + */ + if ( connect ( trap_fd[unit], (struct sockaddr *) &satm, + sizeof(satm)) < 0 ) { + perror ( "connect" ); + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "connect: closing unit %d\n", unit ); + } + close ( trap_fd[unit] ); + trap_fd[unit] = -1; + ilmi_fd[unit] = -1; + continue; + } + + if ( Debug_Level && Log ) { + write_timestamp(); + fprintf ( Log, "***** opened unit %d\n", unit ); + } + /* + * Send coldStart TRAP + */ + if ( Debug_Level > 4 && Log ) { + write_timestamp(); + fprintf ( Log, "===== Sent %d bytes =====\n", + coldStart_Trap[0] ); + hexdump ( (u_char *)&coldStart_Trap[1], coldStart_Trap[0] ); + } + if ( Debug_Level && Log ) { + write_timestamp(); + fprintf ( Log, "\tSend coldStart TRAP to unit %d\n", unit ); + } + last_trap[unit] = time ( (time_t *)NULL ); + write ( trap_fd[unit], (caddr_t)&coldStart_Trap[1], + coldStart_Trap[0] ); + } + + } + + signal ( SIGALRM, ilmi_open ); + alarm ( SLEEP_TIME ); + + return; + +} + +/* + * Send our local IP address for this interface + * + * Arguments: + * s - socket to send message on + * hdr - pointer to internal SNMP header + * + * Returns: + * none + * + */ +void +send_myipnm ( s, hdr ) + int s; + Snmp_Header *hdr; +{ + char intf_name[IFNAMSIZ]; + int namelen = IFNAMSIZ; + struct air_netif_rsp *net_info = NULL; + struct sockaddr_in *sin; + + COPY_RESP ( MyIpNm_Resp ); + + if ( getsockopt ( s, T_ATM_SIGNALING, T_ATM_NET_INTF, + (caddr_t) intf_name, &namelen ) ) { + perror ( "Couldn't get socket name" ); + return; + } + + /* + * Get network interface information for this physical interface + */ + get_netif_info ( intf_name, &net_info ); + if ( net_info == NULL ) + return; + + sin = (struct sockaddr_in *)&net_info->anp_proto_addr; + + /* + * Copy interface's IP address into reply packet + */ + UM_COPY ( (caddr_t)&sin->sin_addr.s_addr, (caddr_t)&Resp_Buf[51], + 4 ); + + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "\tSend NM IP address\n" ); + } + + send_resp ( s, hdr->reqid, Resp_Buf ); + + /* + * Clean up + */ + free ( net_info ); + return; +} + +/* + * Set local NSAP prefix and then reply with our full NSAP address. + * + * Switch will send a SET message with the NSAP prefix after a coldStart. + * We'll set that prefix into HARP and then send a SET message of our own + * with our full interface NSAP address. + * + * Arguments: + * oid - objid from SET message + * hdr - pointer to internal SNMP header + * buf - pointer to SET buffer + * s - socket to send messages on + * + * Returns: + * none + * + */ +void +set_prefix ( oid, hdr, buf, s ) + Objid *oid; + Snmp_Header *hdr; + u_char *buf; + int s; +{ + struct atmsetreq asr; + Atm_addr *aa; + int fd; + int i; + u_char *cpp; + int len; /* PDU length before completion */ + + /* + * If we don't reply to the SET then it keeps getting retransmitted. + */ + buf[14] = PDU_TYPE_GETRESP; + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "\tSend SET_RESPONSE\n" ); + } + send_resp ( s, hdr->reqid, buf ); + + /* + * Build IOCTL request to set prefix + */ + asr.asr_opcode = AIOCS_SET_PRF; + strncpy ( asr.asr_prf_intf, Intf[0].anp_intf, + sizeof(asr.asr_prf_intf ) ); + /* + * Pull prefix out of received Objid + */ + for ( i = 0; i < oid->oid[13]; i++ ) + asr.asr_prf_pref[i] = oid->oid[i + 14]; + + /* + * Pass new prefix to the HARP kernel + */ + fd = socket ( AF_ATM, SOCK_DGRAM, 0 ); + if ( fd < 0 ) + return; + if ( ioctl ( fd, AIOCSET, (caddr_t)&asr ) < 0 ) { + if ( errno != EALREADY ) { + syslog ( LOG_ERR, "ilmid: error setting prefix: %m" ); + if ( Log ) { + write_timestamp(); + fprintf ( Log, "ilmid: errno %d setting prefix\n", + errno ); + } + return; + } + } + close ( fd ); + + /* + * Reload the cfg/intf info with newly set prefix + */ + init_ilmi(); + + aa = &Intf[0].anp_addr; + + /* + * Finish building SET NSAP packet + */ + + COPY_RESP ( NetPrefix_Resp ); + + len = Resp_Buf[0]; + cpp = &Resp_Buf[len + 1]; /* Set to end of response buffer */ + len++; + *cpp++ = aa->address_length; + for ( i = 0; i < aa->address_length; i++ ) { + u_char c = ((u_char *)(aa->address))[i]; + + if ( c > 127 ) { + *cpp++ = ( c >> 7 ) | 0x80; + len++; + c &= 0x7f; + } + *cpp++ = c; + len++; + } + /* + * Pack "set = 1" onto end + */ + *cpp++ = 0x02; + *cpp++ = 0x01; + *cpp++ = 0x01; + len += 3; + + /* + * Go back and patch up lengths... + */ + Resp_Buf[0] = len; + Resp_Buf[4] = (u_char)(len - 4); + Resp_Buf[15] = (u_char)(len - 15); + Resp_Buf[31] = (u_char)(len - 31); + Resp_Buf[35] = (u_char)(len - 35); + Resp_Buf[37] = (u_char)(len - 40); + + /* + * Set reqid + */ + set_reqid ( Resp_Buf, Req_ID++ ); + + /* + * Send SET + */ + if ( Debug_Level > 2 && Log ) { + write_timestamp(); + fprintf ( Log, "===== Send SET: %d bytes =====\n", + Resp_Buf[0] ); + hexdump ( (u_char *)&Resp_Buf[1], Resp_Buf[0] ); + } + write ( s, (caddr_t)&Resp_Buf[1], Resp_Buf[0] ); + + return; + +} + +Objid oid; + +/* + * Parse an ASN_TYPE_SET pdu + * + * Crack apart the various pieces of a SET message. The OBJID being set is + * left in oid which is compared and handled else where. + * + * Arguments: + * bp - pointer to current location in PDU buffer + * + * Returns: + * bp - updated buffer pointer + * 0 - no error + * -1 - error in PDU + * + */ +int +process_set ( bp ) + caddr_t *bp; +{ + caddr_t bufp = *bp; + int pdulen; + int b; + + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "SET:: " ); + } + /* + * Should be SEQUENCE OF + */ + if ( *bufp++ != ASN_SEQUENCE ) { + *bp = bufp; + return ( -1 ); + } + pdulen = asn_get_pdu_len ( &bufp ); + /* + * Should be SEQUENCE OF + */ + if ( *bufp++ != ASN_SEQUENCE ) { + *bp = bufp; + return ( -1 ); + } + pdulen = asn_get_pdu_len ( &bufp ); + /* + * Should be OBJID + */ + if ( *bufp++ != ASN_OBJID ) { + *bp = bufp; + return ( -1 ); + } + asn_get_objid ( &bufp, &oid ); + /* + * Should be <= value> + */ + switch ( *bufp++ ) { + case ASN_INTEGER: + b = asn_get_int ( &bufp ); + if ( Debug_Level > 5 && Log ) { + write_timestamp(); + fprintf ( Log, "Value = %d\n", b ); + } + break; + case ASN_OBJID: + break; + } + + /* + * Return updated pointer + */ + *bp = bufp; + + return ( 0 ); +} + +int specific_trap; +int generic_trap; +int trap_time; +u_char trap_ip[5]; +Objid trap_oid; +Objid extra_trap_oid; + +/* + * Parse an ASN_TYPE_TRAP pdu + * + * Crack apart the various pieces of a TRAP message. The information elements are + * left in global space and used elsewhere if anyone cares (which they currently don't). + * + * Arguments: + * bp - pointer to current location in PDU buffer + * sd - socket descriptor pdu arrived on + * + * Returns: + * bp - updated buffer pointer + * 0 - no error + * -1 - error in PDU + * + */ +int +process_trap ( bp, sd ) + caddr_t *bp; + int sd; +{ + caddr_t bufp = *bp; + int pdulen; + int i; + + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "TRAP:: " ); + } + /* + * Should be pdulen + */ + pdulen = *bufp++; + /* + * Should be OBJID + */ + if ( *bufp++ != ASN_OBJID ) { + if ( Log ) + fprintf ( Log, "\n" ); + *bp = bufp; + return ( -1 ); + } + asn_get_objid ( &bufp, &trap_oid ); + /* + * First oid coded as 40 * X + Y + */ + if ( Debug_Level > 5 && Log ) { + write_timestamp(); + fprintf ( Log, "%d.%d", trap_oid.oid[1] / 40, + trap_oid.oid[1] % 40 ); + for ( i = 2; i <= trap_oid.oid[0]; i++ ) + fprintf ( Log, ".%d", trap_oid.oid[i] ); + fprintf ( Log, "\n" ); + } + /* + * Should be OCTET STRING + */ + if ( *bufp++ != ASN_IPADDR ) { + if ( Debug_Level > 5 && Log ) { + write_timestamp(); + fprintf ( Log, "Expected IP ADDRESS\n" ); + } + *bp = bufp; + return ( -1 ); + } + asn_get_octet ( &bufp, trap_ip ); + if ( Debug_Level > 5 && Log) { + write_timestamp(); + fprintf ( Log, "\tIP: %d.%d.%d.%d", + trap_ip[0], trap_ip[1], trap_ip[2], trap_ip[3] ); + } + /* + * Should be Generic Trap followed by Specific Trap + */ + if ( *bufp++ != ASN_INTEGER ) { + if ( Log ) + fprintf ( Log, "\n" ); + *bp = bufp; + return ( -1 ); + } + generic_trap = asn_get_int ( &bufp ); + if ( Debug_Level > 5 && Log ) { + fprintf ( Log, " Generic Trap: %s (%d)", + Traps[generic_trap], generic_trap ); + } + if ( *bufp++ != ASN_INTEGER ) { + if ( Log ) + fprintf ( Log, "\n" ); + *bp = bufp; + return ( -1 ); + } + specific_trap = asn_get_int ( &bufp ); + if ( Debug_Level > 5 && Log ) { + fprintf ( Log, " Specific Trap: 0x%x\n", + specific_trap ); + } + /* + * Should be TIMESTAMP + */ + if ( *bufp++ != ASN_TIMESTAMP ) { + if ( Log ) + fprintf ( Log, "\n" ); + *bp = bufp; + return ( -1 ); + } + trap_time = asn_get_int ( &bufp ); + if ( Debug_Level > 5 && Log ) { + write_timestamp(); + fprintf ( Log, "\tTimestamp: %d seconds", trap_time ); + } + /* + * Should be SEQUENCE OF + */ + if ( *bufp++ != ASN_SEQUENCE ) { + *bp = bufp; + return ( -1 ); + } + pdulen = asn_get_pdu_len ( &bufp ); + /* + * Should be OBJID + */ + if ( *bufp++ != ASN_OBJID ) { + *bp = bufp; + return ( -1 ); + } + asn_get_objid ( &bufp, &extra_trap_oid ); + if ( Debug_Level > 5 && Log ) { + write_timestamp(); + fprintf ( Log, "\tExtra Objid: " ); + fprintf ( Log, "%d.%d", extra_trap_oid.oid[1] / 40, + extra_trap_oid.oid[1] % 40 ); + for ( i = 2; i <= extra_trap_oid.oid[0]; i++ ) + fprintf ( Log, ".%d", extra_trap_oid.oid[i] ); + fprintf ( Log, "\n" ); + } + /* + * Whole thing ended with a NULL + */ + bufp++; + bufp++; + + /* + * Return updated pointer + */ + *bp = bufp; + + if ( generic_trap == 0 ) { + write ( sd, (caddr_t)&coldStart_Trap[1], + coldStart_Trap[0] ); + } + + return ( 0 ); + +} + +u_char No_Such[] = { 37, + 0x30, 0x82, 0x00, 0x00, + 0x02, 0x01, 0x00, + 0x04, 0x04, 0x49, 0x4c, 0x4d, 0x49, + PDU_TYPE_GETRESP, + 0x00, + 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x01, 0x02, + 0x02, 0x01, 0x01, + 0x30, 0x82, 0x00, 0x00, + 0x30, 0x82, 0x00, 0x00, + 0x06, 0x00 + }; +void +send_no_such ( s, Hdr, op ) + int s; + Snmp_Header *Hdr; + Objid *op; +{ + u_char *cp, *cpp; + int len; + int i; + + len = No_Such[0]; + + UM_COPY ( No_Such, Resp_Buf, len + 1 ); + + cp = cpp = (u_char *)&Resp_Buf[len]; + + /* + * Copy OID into response buffer + */ + *cp++ = op->oid[0]; + for ( i = 1; i <= op->oid[0]; i++ ) { + u_int c = op->oid[i]; + + if ( c > 127 ) { + *cp++ = ( c >> 7 ) | 0x80; + len++; + c &= 0x7f; + /* + * Increment OID length + */ + *cpp += 1; + } + *cp++ = c; + len++; + } + /* + * Finish off with a NULL + */ + *cp++ = 0x05; + *cp++ = 0x00; + len += 2; + + /* + * Patch up all the length locations + */ + Resp_Buf[0] = len; + Resp_Buf[4] = len - 4; + Resp_Buf[15] = len - 15; + Resp_Buf[31] = len - 31; + Resp_Buf[35] = len - 35; + + /* + * Send Response + */ + send_resp ( s, Hdr->reqid, Resp_Buf ); + + return; +} + +/* + * Utility to strip off any leading path information from a filename + * + * Arguments: + * path pathname to strip + * + * Returns: + * fname striped filename + * + */ +char * +basename ( path ) + char *path; +{ + char *fname; + + if ( ( fname = (char *)strrchr ( path, '/' ) ) != NULL ) + fname++; + else + fname = path; + + return ( fname ); +} + +/* + * Increment Debug Level + * + * Catches SIGUSR1 signal and increments value of Debug_Level + * + * Arguments: + * sig - signal number + * + * Returns: + * none - Debug_Level incremented + * + */ +void +Increment_DL ( sig ) + int sig; +{ + Debug_Level++; + if ( Debug_Level && Log == (FILE *)NULL ) + if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL ) + Log = NULL; + else + setbuf ( Log, NULL ); + signal ( SIGUSR1, Increment_DL ); + alarm ( SLEEP_TIME ); + return; +} + +/* + * Decrement Debug Level + * + * Catches SIGUSR2 signal and decrements value of Debug_Level + * + * Arguments: + * sig - signal number + * + * Returns: + * none - Debug_Level decremented + * + */ +void +Decrement_DL ( sig ) + int sig; +{ + Debug_Level--; + if ( Debug_Level <= 0 ) { + Debug_Level = 0; + if ( Log ) { + fclose ( Log ); + Log = NULL; + } + } + signal ( SIGUSR2, Decrement_DL ); + alarm ( SLEEP_TIME ); + return; +} + +main ( argc, argv ) + int argc; + char *argv[]; +{ + u_char buf[256], set_buf[256]; + char community[1024]; + u_char *bufp; + int s; + int c; + int foregnd = 0; /* run in the foreground? */ + int pdulen; + int version; + int pdutype; + int reqid; + int error_status; + int error_ptr; + int b; + int i; + int lerr = 0; + int Reset = 0; /* Should we send a coldStart and exit? */ + Snmp_Header *Hdr; + int n; + + /* + * What are we running as? (argv[0]) + */ + progname = strdup ( (char *)basename ( argv[0] ) ); + /* + * What host are we + */ + gethostname ( hostname, sizeof ( hostname ) ); + + /* + * Ilmid needs to run as root to set prefix + */ + if ( getuid() != 0 ) { + fprintf ( stderr, "%s: needs to run as root.\n", progname ); + exit ( -1 ); + } + + /* + * Parse arguments + */ + while ( ( c = getopt ( argc, argv, "d:fr" ) ) != EOF ) + switch ( c ) { + case 'd': + Debug_Level = atoi ( optarg ); + break; + case 'f': + foregnd++; + break; + case 'r': + Reset++; + break; + case '?': + fprintf ( stderr, "usage: %s [-d level] [-f] [-r]\n", + progname ); + exit ( -1 ); +/* NOTREACHED */ + break; + } + + /* + * If we're not doing debugging, run in the background + */ + if ( foregnd == 0 ) { +#ifdef sun + int pid, fd; + + if ( ( pid = fork() ) < 0 ) { + fprintf ( stderr, "fork failed\n" ); + exit ( 1 ); + } else if (pid != 0) { + /* Parent process - exit and allow child to run */ + exit ( 0 ); + } + /* Child process */ + if ( ( lerr = setpgrp ( 0, getpid() ) ) < 0 ) { + fprintf ( stderr, "Can't set process group" ); + exit ( 1 ); + } + if ( ( fd = open ( "/dev/tty", O_RDWR ) ) >= 0 ) { + ioctl ( fd, TIOCNOTTY, (char *)NULL ); + close ( fd ); + } + /* close all open descriptors */ + for ( fd = 3; fd < getdtablesize(); fd++ ) + close ( fd ); +#else + if ( daemon ( 0, 0 ) ) + err ( 1, "Can't fork" ); +#endif + } else + setbuf ( stdout, NULL ); + + signal ( SIGUSR1, Increment_DL ); + signal ( SIGUSR2, Decrement_DL ); + + /* + * Open log file + */ + if ( Debug_Level ) + if ( ( Log = fopen ( LOG_FILE, "a" ) ) == NULL ) + Log = NULL; + else + setbuf ( Log, NULL ); + + /* + * Get our startup time + */ + (void) gettimeofday ( &starttime, NULL ); + starttime.tv_sec--; + starttime.tv_usec += 1000000; + + /* + * Reset all the interface descriptors + */ + for ( i = 0; i < MAX_UNITS; i++ ) { + trap_fd[i] = -1; + last_trap[i] = (time_t)0; + ilmi_fd[i] = -1; + } + /* + * Try to open all the interfaces + */ + ilmi_open (); + + /* + * If we're just sending a coldStart end exiting... + */ + if ( Reset ) { + for ( i = 0; i < MAX_UNITS; i++ ) + if ( trap_fd[i] >= 0 ) { + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "Close trap_fd[%d]: %d\n", + i, trap_fd[i] ); + } + close ( trap_fd[i] ); + } + exit ( 2 ); + } + + /* + * For ever... + */ + for ( ; ; ) { + int maxfd = 0; + int count; + struct timeval tvp; + fd_set rfd; + time_t curtime; + + ilmi_open(); + + /* + * SunOS CC doesn't allow automatic aggregate initialization. + * Make everybody happy and do it here... + */ + tvp.tv_sec = 15; + tvp.tv_usec = 0; + + curtime = time ( (time_t *)NULL ); + + /* + * Check for TRAP messages + */ + FD_ZERO ( &rfd ); + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "Check Traps: " ); + } + for ( i = 0; i < MAX_UNITS; i++ ) { + if ( Debug_Level > 1 && Log ) + fprintf ( Log, "trap_fd[%d]: %d ", i, trap_fd[i] ); + if ( trap_fd[i] != -1 ) { + /* + * If we haven't sent a coldStart trap recently, + * send one now + */ + if ( last_trap[i] + TRAP_TIME < curtime ) { + last_trap[i] = curtime; + /* + * Send coldStart TRAP + */ + if ( Debug_Level > 4 && Log ) { + write_timestamp(); + fprintf ( Log, "===== Sent %d bytes =====\n", + coldStart_Trap[0] ); + hexdump ( (u_char *)&coldStart_Trap[1], + coldStart_Trap[0] ); + } + if ( Debug_Level && Log ) { + write_timestamp(); + fprintf ( Log, + "\tSend coldStart TRAP to unit %d\n", i ); + } + write ( trap_fd[i], (caddr_t)&coldStart_Trap[1], + coldStart_Trap[0] ); + } + if ( (trap_fd[i] >= 0) && + FD_SET ( trap_fd[i], &rfd )) { + maxfd = MAX ( maxfd, trap_fd[i] ); + } + } + } + if ( Debug_Level > 1 && Log ) + fprintf ( Log, "maxfd: %d\n", maxfd ); + + if ( maxfd ) { + count = select ( maxfd + 1, &rfd, NULL, NULL, &tvp ); + + if ( count > 0 ) { + for ( i = 0; i < MAX_UNITS; i++ ) { + if ( trap_fd[i] >= 0 && FD_ISSET ( trap_fd[i], &rfd ) ) { + s = trap_fd[i]; + + n = read ( s, (caddr_t)&buf[1], sizeof(buf) - 1 ); + if ( n == -1 && ( errno == ECONNRESET || + errno == EBADF ) ) { + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, + "Bad read: close trap_fd[%d]: %d\n", + i, trap_fd[i] ); + } + close ( trap_fd[i] ); + trap_fd[i] = -1; + ilmi_fd[i] = -1; + } + if ( n ) { + buf[0] = n; + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "***** Read %d bytes *****\n", + n ); + hexdump ( (caddr_t)&buf[1], n ); + } + bufp = buf; + /* + * Skip length byte + */ + bufp++; + /* + * Crack the header + */ + if ( ( Hdr = asn_get_header ( &bufp ) ) == NULL ) + continue; + pdutype = Hdr->pdutype; + /* + * Only interested in TRAP messages + */ + switch ( pdutype ) { + /* + * FORE switches often go straight to SET prefix + * after receiving a coldStart TRAP from us + */ + case PDU_TYPE_SET: + /* + * Make a copy of this PDU so that a + * SET NSAP prefix can reply to it. + */ + UM_COPY ( buf, set_buf, sizeof(buf) ); + + lerr = process_set ( &bufp ); + /* + * Can't do a simple oid_cmp since we + * don't yet know what the prefix is. + * If it looks like a SET netPrefix.0, + * then compare the portion leading up + * to the NSAP prefix part. + */ + if ( oid.oid[0] == 26 ) { + oid.oid[0] = 12; + if ( oid_cmp ( &setprefix, &oid ) == 0 ) { + oid.oid[0] = 26; + set_prefix ( &oid, Hdr, set_buf, s ); + } + } + /* + * We now move from awaiting TRAP to processing ILMI + */ + ilmi_fd[i] = trap_fd[i]; + trap_fd[i] = -1; + break; + case PDU_TYPE_TRAP: + lerr = process_trap ( &bufp, trap_fd[i] ); + /* + * We now move from awaiting TRAP to processing ILMI + */ + ilmi_fd[i] = trap_fd[i]; + trap_fd[i] = -1; + break; + } + } /* if n */ + } /* if FD_ISSET */ + } /* for i */ + } /* if count */ + } + + /* + * Reset from TRAP checking + */ + maxfd = 0; + errno = 0; + /* + * Check for ILMI messages + */ + FD_ZERO ( &rfd ); + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "Check Ilmis: " ); + } + for ( i = 0; i < MAX_UNITS; i++ ) { + if ( Debug_Level > 1 && Log ) + fprintf ( Log, "ilmi_fd[%d]: %d ", i, ilmi_fd[i] ); + if ( ilmi_fd[i] != -1 ) { + if ( (ilmi_fd[i] >= 0) && + FD_SET ( ilmi_fd[i], &rfd )) { + maxfd = MAX ( maxfd, ilmi_fd[i] ); + } + } + } + if ( Debug_Level > 1 && Log ) + fprintf ( Log, "maxfd: %d\n", maxfd ); + + if ( maxfd ) { + count = select ( maxfd + 1, &rfd, NULL, NULL, &tvp ); + + if ( count > 0 ) { + for ( i = 0; i < MAX_UNITS; i++ ) { + if ( ilmi_fd[i] >= 0 && FD_ISSET ( ilmi_fd[i], &rfd ) ) { + + s = ilmi_fd[i]; + + n = read ( s, (caddr_t)&buf[1], sizeof(buf) - 1 ); + if ( n == -1 && ( errno == ECONNRESET || + errno == EBADF ) ) { + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, + "Bad read: close ilmi_fd[%d]: %d\n", + i, ilmi_fd[i] ); + } + close ( ilmi_fd[i] ); + trap_fd[i] = -1; + ilmi_fd[i] = -1; + } + if ( n ) { + buf[0] = n; + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, + "***** Read %d bytes *****\n", + n ); + hexdump ( (caddr_t)&buf[1], n ); + } + bufp = buf; + /* + * Skip length byte + */ + bufp++; + /* + * Crack the header + */ + if ( ( Hdr = asn_get_header ( &bufp ) ) + == NULL ) + continue; + pdutype = Hdr->pdutype; + + /* + * Do the operation... + */ + switch ( pdutype ) { + + case PDU_TYPE_GET: + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "GET:: " ); + } + /* + * Should be SEQUENCE OF + */ + if ( *bufp++ != ASN_SEQUENCE ) { + lerr = 1; + break; + } + pdulen = asn_get_pdu_len ( &bufp ); + /* + * Should be SEQUENCE OF + */ + if ( *bufp++ != ASN_SEQUENCE ) { + lerr = 1; + break; + } + pdulen = asn_get_pdu_len ( &bufp ); + /* + * Should be OBJID + */ + if ( *bufp++ != ASN_OBJID ) { + lerr = 1; + break; + } + asn_get_objid ( &bufp, &oid ); + /* + * Ended with a NULL + */ + bufp++; + bufp++; + /* + * If GET sysObjId.0 + */ + if (oid_cmp(&sysObjId, &oid) == 0 ) { + send_resp ( s, Hdr->reqid, + sysObjId_Resp ); + + } else + /* + * If GET sysUpTime.0 + */ + if (oid_cmp(&sysUpTime, &oid) == 0 ) { + send_uptime_resp ( s, + Hdr->reqid ); + } else + /* + * If GET myIpNm.0 + */ + if ( oid_cmp ( &myipnm, &oid ) == 0 ) { + send_myipnm ( s, Hdr ); + } else + /* + * If GET uniType.0 + */ + if ( oid_cmp ( &unitype, &oid ) == 0 ) { + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, + "\tSend uniType\n" ); + } + send_resp ( s, Hdr->reqid, + UniType_Resp ); + } else + /* + * If GET uniVer.0 + */ + if ( oid_cmp ( &univer, &oid ) == 0 ) { + int p = UniVer_Resp[0]; + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, + "\tSend uniVer\n" ); + } + switch (Intf[i].anp_sig_proto) { + case ATM_SIG_UNI30: + UniVer_Resp[p] = + UNIVER_UNI30; + break; + case ATM_SIG_UNI31: + UniVer_Resp[p] = + UNIVER_UNI31; + break; + case ATM_SIG_UNI40: + UniVer_Resp[p] = + UNIVER_UNI40; + break; + } + send_resp ( s, Hdr->reqid, + UniVer_Resp ); + } else + /* + * If GET devType.0 + */ + if ( oid_cmp ( &devtype, &oid ) == 0 ) { + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, + "\tSend devType\n" ); + } + send_resp ( s, Hdr->reqid, + DevType_Resp ); + } else + /* + * If GET foreSigGrp....0 + */ + if (oid_cmp(&foresiggrp, &oid) == 0) { + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, + "\tSend noSuchVar\n" ); + } + send_resp ( s, Hdr->reqid, + NoSuchFore_Resp ); + } else + if ( oid_cmp(&layeridx, &oid) == 0 ) { + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, + "\t*** LayerIndex\n" ); + } + } else + if ( oid_cmp(&maxvcc, &oid) == 0 ) { + send_resp ( s, Hdr->reqid, + maxVCC_Resp ); + } else + if ( oid_cmp ( &portidx, &oid ) == 0 ) { + int p = PortIndex_Resp[0]; + PortIndex_Resp[p] = i + 1; + send_resp ( s, Hdr->reqid, + PortIndex_Resp ); + } else + send_no_such ( s, Hdr, &oid ); + break; + + case PDU_TYPE_GETNEXT: + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, "GET_NEXT:: " ); + } + /* + * Should be SEQUENCE OF + */ + if ( *bufp++ != ASN_SEQUENCE ) { + lerr = 1; + break; + } + pdulen = asn_get_pdu_len ( &bufp ); + /* + * Should be SEQUENCE OF + */ + if ( *bufp++ != ASN_SEQUENCE ) { + lerr = 1; + break; + } + pdulen = asn_get_pdu_len ( &bufp ); + /* + * Should be OBJID + */ + if ( *bufp++ != ASN_OBJID ) { + lerr = 1; + break; + } + asn_get_objid ( &bufp, &oid ); + /* + * Ended with a NULL + */ + bufp++; + bufp++; + /* + * If this is a GET_NEXT netPrefix then + * the other side probably restarted + * and is looking for a table empty + * indication before restarting the + * ILMI protocol. + */ + if ( oid_cmp(&netpfx_oid, &oid) == 0 ) { + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, + "\tSend GET_RESP:\n" ); + } + send_resp ( s, Hdr->reqid, + GetNext_Resp ); + } + break; + + case PDU_TYPE_GETRESP: + if ( Debug_Level > 1 && Log ) { + write_timestamp(); + fprintf ( Log, + "GET_RESP:: \n" ); + } + /* + * Ignore any responses to our GETs. + * (We don't send any GETs.) + */ + break; + + case PDU_TYPE_SET: + /* + * Make a copy of this PDU so that a + * SET NSAP prefix can reply to it. + */ + UM_COPY ( buf, set_buf, sizeof(buf) ); + + if ( process_set ( &bufp ) < 0 ) + break; + + /* + * Can't do a simple oid_cmp since we + * don't know what the prefix is yet. + * If it looks like a SET netPrefix.0, + * then compare the portion leading up + * to the NSAP prefix part. + */ + if ( oid.oid[0] == 26 ) { + oid.oid[0] = 12; + if ( oid_cmp(&setprefix,&oid) + == 0 ) { + oid.oid[0] = 26; + set_prefix ( &oid, Hdr, + set_buf, s ); + } + } + break; + + case PDU_TYPE_TRAP: + lerr = process_trap ( &bufp, s ); + break; + } + /* + * Forget about this PDU + */ + free ( Hdr ); + Hdr = NULL; + + } /* end of read(s) */ + } /* end if FD_ISSET(s) */ + } /* end of for ( i... */ + } /* end of if ( count ) */ + } else { + sleep ( SLEEP_TIME ); + } + } /* end of for ever */ + +} + diff --git a/share/examples/atm/NOTES b/share/examples/atm/NOTES new file mode 100644 index 0000000..6317188 --- /dev/null +++ b/share/examples/atm/NOTES @@ -0,0 +1,54 @@ + + HARP Notes + 1998-09-14 + +This is a list of currently known incompatibilities and miscellaneous gotchas +in HARP. + +To report new items, please send mail to harp-bugs@magic.net. + +================================================================================ + + +Efficient Driver and DMA sizes +============================== + +The Efficient adapter moves PDUs between host memory and adapter memory with +the help of DMA descriptor lists. Each DMA descriptor consists of two words. +Word 0 contains a DMA type identifier and a repetition count. Word 1 contains +the physical (not virtual) host buffer address. Each DMA type is really an +encoding of the burst size for the DMA. (See /usr/src/sys/dev/hea/eni.h for +more on the DMA types.) HARP was originally developed using burst sizes of +8_WORD, 4_WORD, and 1_WORD sizes. Each DMA request would be built to first +move as much data as possible using an 8_WORD burst. This should leave 0-7 +words left over. If there were more than 3 words remaining, a 4_WORD DMA burst +would be scheduled. The remaining data must then be 0-3 words in length and +would be moved with 1_WORD bursts. The use of large burst sizes makes more +efficient use of DMA by performing the same amount of work in fewer cycles. + +Several users have reported problems with DMA which were characterized by error +messages of the form: + + "eni_output: Transmit drain queue is full. Resources will be lost." +or + "eni_output: not enough room in DMA queue". + +It was determined that these systems do not support the use of four- or +eight-word DMA bursts. To resolve this problem, HARP now #ifdef's around the +8_WORD and 4_WORD DMA setup and #undef's both values by default. This results +in the default operation of the Efficient driver to use only 1_WORD DMA bursts. + +If you wish to experiment with larger DMA bursts, you can edit the file +/usr/src/sys/dev/hea/eni_transmit.c and change the #undef to a #define for +DMA_USE_8WORD and/or DMA_USE_4WORD. You will need to rebuild and install your +kernel for this change to take effect. + +We are exploring solutions which would allow HARP to determine which DMA bursts +are supported by the system at run-time. This would allow the Efficient device +driver to make use of larger, more efficient burst sizes where supported +without halting on systems which can't support the larger sizes. + + + + @(#) $Id: NOTES,v 1.1 1997/08/22 22:11:17 mks Exp $ + diff --git a/share/examples/atm/README b/share/examples/atm/README new file mode 100644 index 0000000..73aa747 --- /dev/null +++ b/share/examples/atm/README @@ -0,0 +1,140 @@ + + =================================== + HARP | Host ATM Research Platform + =================================== + + HARP 3 + + +What is this stuff? +------------------- +The Advanced Networking Group (ANG) at the Minnesota Supercomputer Center, +Inc. (MSCI), as part of its work on the MAGIC Gigabit Testbed, developed +the Host ATM Research Platform (HARP) software, which allows IP hosts to +communicate over ATM networks using standard protocols. It is intended to +be a high-quality platform for IP/ATM research. + +HARP provides a way for IP hosts to connect to ATM networks. It supports +standard methods of communication using IP over ATM. A host's standard IP +software sends and receives datagrams via a HARP ATM interface. HARP provides +functionality similar to (and typically replaces) vendor-provided ATM device +driver software. + +HARP includes full source code, making it possible for researchers to +experiment with different approaches to running IP over ATM. HARP is +self-contained; it requires no other licenses or commercial software packages. + +HARP implements support for the IETF Classical IP model for using IP over ATM +networks, including: + + o IETF ATMARP address resolution client + o IETF ATMARP address resolution server + o IETF SCSP/ATMARP server + o UNI 3.1 and 3.0 signalling protocols + o Fore Systems's SPANS signalling protocol + + + +What's supported +---------------- +The following are supported by HARP 3: + + o ATM Host Interfaces + - FORE Systems, Inc. SBA-200 and SBA-200E ATM SBus Adapters + - FORE Systems, Inc. PCA-200E ATM PCI Adapters + - Efficient Networks, Inc. ENI-155p ATM PCI Adapters + + o ATM Signalling Protocols + - The ATM Forum UNI 3.1 signalling protocol + - The ATM Forum UNI 3.0 signalling protocol + - The ATM Forum ILMI address registration + - FORE Systems's proprietary SPANS signalling protocol + - Permanent Virtual Channels (PVCs) + + o IETF "Classical IP and ARP over ATM" model + - RFC 1483, "Multiprotocol Encapsulation over ATM Adaptation Layer 5" + - RFC 1577, "Classical IP and ARP over ATM" + - RFC 1626, "Default IP MTU for use over ATM AAL5" + - RFC 1755, "ATM Signaling Support for IP over ATM" + - RFC 2225, "Classical IP and ARP over ATM" + - RFC 2334, "Server Cache Synchronization Protocol (SCSP)" + - Internet Draft draft-ietf-ion-scsp-atmarp-00.txt, + "A Distributed ATMARP Service Using SCSP" + + o ATM Sockets interface + - The file atm-sockets.txt contains further information + + +What's not supported +-------------------- +The following major features of the above list are not currently supported: + + o UNI point-to-multipoint support + o Driver support for Traffic Control/Quality of Service + o SPANS multicast and MPP support + o SPANS signalling using Efficient adapters + + +For further information +----------------------- +For additional information about HARP, please see: + + http://www.msci.magic.net + + +Suggestions and Problem Reports +------------------------------- +While HARP is made available "as is" and is not supported, ANG is continuing +development of HARP. We welcome suggestions for new or enhanced features, +summaries of your experience with HARP, as well as reports of problems which +you may experience. Feel free to contact us at harp-bugs@magic.net. + +ANG is maintaining a mail list of those who wish to share their experiences +with HARP, learn of others' experiences, or receive information about future +releases of HARP. The HARP mailing list is at harp@magic.net. To be added +to the list, send email to harp-request@magic.net. + + +Acknowledgments +--------------- +This software was developed under the sponsorship of the Defense Advanced +Research Projects Agency (DARPA). + + +Citing HARP +----------- +When citing HARP in published works, please use the following citation: + +Host ATM Research Platform (HARP), Network Computing Services, Inc. +This software was developed with the support of the Defense Advanced +Research Projects Agency (DARPA). + + +Copyright and Permitted Use +--------------------------- +The Host ATM Research Platform ("HARP") software (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. + +Portions of this Software include materials copyrighted by the Regents of +the University of California and by Sun Microsystems, Inc. The applicable +copyright notices are reproduced in the files where the material appears. + +-------------------------------------------------------------------------------- + + @(#) $Id: README,v 1.4 1998/08/07 19:23:36 mks Exp $ + diff --git a/share/examples/atm/Startup b/share/examples/atm/Startup new file mode 100644 index 0000000..4c0ec7d --- /dev/null +++ b/share/examples/atm/Startup @@ -0,0 +1,127 @@ +HARP ATM Startup Configuration Instructions +=========================================== + +The following steps are required in order to use the HARP ATM software. +See the file atm-config.sh for an example ATM startup script. + +1. Each ATM physical interface must be configured with one or more network + interfaces. The physical interfaces are named: + + FORE Systems: hfa0, hfa1, ... + Efficient Networks: hea0, hea1, ... + + The network interface names and the number of network interfaces for a + particular physical interface are specified via the atm command. The + network interface name prefix may be any alphabetic string, but the + generated network interface names must be unique amongst all network + interfaces, including non-ATM interfaces. + + To configure the network interfaces, type: + + atm set netif <interface_name> <netif_prefix> <netif_count> + + For example, the command: + + atm set netif hfa0 ni 3 + + will generate the network interfaces ni0, ni1 and ni2 on the physical + interface hfa0. + + For further details, see the man page atm(8). + + +2. Each ATM network interface (netif) must be configured with an IP network + address. Each network interface must be on a different IP subnet. + + To configure the network interface, type: + + ifconfig <netif_name> <IP_address> up + + +3. Each ATM physical interface must have a signalling manager attached. The + interfaces may have the same or different signalling managers. + + To attach a signalling manager, type: + + atm attach <interface_name> <signalling_manager_name> + + where <signalling_manager_name> may be: + + sigpvc - to only support PVCs on the interface; + spans - to run FORE Systems SPANS signalling protocol across + the interface, plus support of PVCs; + uni30 - to run ATM Forum UNI 3.0 signalling protocol across + the interface, plus support of PVCs; + uni31 - to run ATM Forum UNI 3.1 signalling protocol across + the interface, plus support of PVCs; + + For further details, see the man page atm(8). + + +4. Each of the host's PVCs (if any) must be defined. + + To define a PVC, type: + + atm add pvc <interface_name> <vpi> <vci> <aal> <encaps> <owner> .... + + where <interface_name> is the name of the ATM physical interface + over which the PVC is being defined; + <vpi> is the VPI value for the PVC; + <vci> is the VCI value for the PVC; + <aal> is the AAL type which the PVC endpoints will use; + <encaps> is the encapsulation which the PVC endpoints will use; + <owner> specifies the the owner of the PVC, which may be: + ip - the PVC is used for IP traffic; + + additional parameters may be required, depending on the PVC owner: + + for owner=ip, + <netif_name> is the name of the PVC's network interface; + <dst> specifies the IP address at the remote end of this PVC; + + For further details, see the man page atm(8). + + +5. HARP includes an ILMI daemon, which will perform host address registration + with the ATM switch for ATM Forum UNI interfaces. If ILMI support is + available and activated in the ATM switch and the ILMI daemon is running + (see ilmid(8)), no further registration procedures are required. + The 'atm set prefix' command is not needed in this case. + + If ILMI address registration support is not available or activated, then + the host must be manually registered with its switch. There should be + a user command available on the switch in order to do the registration. + + For example, if you are using a FORE Systems switch, you should enter + the following AMI command: + + > conf nsap route new <host_nsap> 152 <switch_port> 0 + + If you are using a Cisco LightStream 1010 switch, you would use the + following configuration command: + + > atm route <host_nsap> atm <atm_interface_#> internal + + For ATM Forum UNI interfaces, the 'atm set prefix' command must also + be issued when not using ILMI address registration. + + +6. HARP includes support for the Server Cache Synchronization Protocol (SCSP), + which can synchronize the ATMARP caches of multiple ATMARP servers. + Obviously, this is only useful on hosts which are ATMARP servers. + + To run SCSP between servers, two daemons, scspd and atmarpd, must be + started. Scspd implements the SCSP protocol and atmarpd provides an + interface between scspd and the ATMARP server in the kernel. Scspd + requires a configuration file. It will look for a configuration + file at /etc/scspd.conf unless told otherwise. + + An example of commands to start the two daemons is: + + # scspd + # atmarpd <netif> + + See the man pages scspd(8) and atmarpd(8) for further information. + + @(#) $Id: Startup,v 1.6 1998/08/26 21:37:42 johnc Exp $ + diff --git a/share/examples/atm/atm-config.sh b/share/examples/atm/atm-config.sh new file mode 100755 index 0000000..40606d4 --- /dev/null +++ b/share/examples/atm/atm-config.sh @@ -0,0 +1,88 @@ +#! /bin/sh +# +# +# =================================== +# 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. +# +# @(#) $Id$ +# +# + +# +# Sample script to load and configure ATM software +# + +# +# Download FORE microcode into adapter(s) +# +# This step is only required if you are using FORE ATM adapters. +# This assumes that the FORE microcode file pca200e.bin is in /etc. +# See the file fore-microcode.txt for further details. +# +/sbin/fore_dnld -d /etc + +# +# Define network interfaces +# +/sbin/atm set netif hfa0 <netif_prefix> 1 + +# +# Configure physical interfaces +# +/sbin/atm attach hfa0 uni31 + +# +# Start ILMI daemon (optional) +# +/sbin/ilmid + +# +# Set ATM address prefix +# +# Only need to set prefix if using UNI and not using ILMI daemon +# +#/sbin/atm set prefix hfa0 <nsap_prefix> + +# +# Configure network interfaces +# +/sbin/ifconfig <netif> <ip_addr> netmask + up +/sbin/atm set arpserver <netif> <atm_address> + +# +# Configure PVCs (optional) +# +#/sbin/atm add pvc hfa0 <vpi> <vci> aal5 null ip <netif> <ip_addr> + +# +# Start SCSP daemons (optional) +# +# This step is only required if your host is configured as an ATMARP server +# and you wish to synchronize its cache with the cache(s) of some other +# server(s). Scspd will look for its configuration file at /etc/scspd.conf. +# +#/usr/sbin/scspd +#/usr/sbin/atmarpd <netif> ... + +exit 0 + diff --git a/share/examples/atm/atm-sockets.txt b/share/examples/atm/atm-sockets.txt new file mode 100644 index 0000000..258a565 --- /dev/null +++ b/share/examples/atm/atm-sockets.txt @@ -0,0 +1,340 @@ + + HARP Native ATM Sockets API + =========================== + +ATM sockets are an extension to the traditional BSD sockets API to allow +direct user-level access to native ATM protocol services. The ATM sockets +extensions are implemented via the addition of a new protocol family (PF_ATM) +and a new socket address structure (struct sockaddr_atm). + +The HARP implementation of native ATM sockets capabilities is intended to be +conformant with The Open Group specifications (with known differences listed +below) as defined in the following document: + + The Open Group: Networking Services (XNS) Issue 5 + ISBN 1-85912-165-9 + http://www.rdg.opengroup.org/public/pubs/catalog/c523.htm + +And in particular, it is based on the following ATM-specific sections in the +above document: + + ATM Transport Protocol Information for Sockets + ATM Transport Protocol Information for XTI + ATM Transport Headers + +The ATM sockets API is an implementation based on the definitions and +descriptions set forth in the following document: + + The ATM Forum: Native ATM Services: Semantic Description, Version 1.0 + af-saa-0048.000 + http://www.atmforum.com/atmforum/specs/approved.html + + +Using the HARP Implementation +----------------------------- +This document only provides the HARP-specific information necessary for using +the ATM sockets API. Please refer to the XNS document described above for +all of the general interface specifications. There is also sample source +code for an ATM sockets application included at the end of this document. + +All user definitions for the HARP ATM sockets implementation are contained +in the file /usr/include/netatm/atm.h. This file must be included in the +user's C program source file. In this file, all HARP extensions to the base +XNS specifications are denoted with a comment string of "XNS_EXT". + + +HARP Extensions to XNS Issue 5 +------------------------------ +o Socket address structure for ATM addresses + + An ATM socket address structure was not specifically defined by XNS, + although the t_atm_sap structure was defined to be used as an ATM protocol + address. Thus, HARP has defined an ATM socket address (using address + family AF_ATM) as a 'struct sockaddr_atm', which contains 'struct t_atm_sap' + as the protocol address. This structure (properly cast) must be used on + all ATM socket system calls requiring a 'struct sockaddr' parameter. + +o Network Interface Selection socket option (T_ATM_NET_INTF) + + This option is used to specify the name of the network interface to be + used to route an outgoing ATM call using a socket connection. This option + is only needed when there are multiple ATM network interfaces defined on a + system. If this option is not set, then the first network interface on + the first physical ATM interface defined will be used. + + See the sample application below for an example of the use of this option. + +o LLC Multiplexing socket option (T_ATM_LLC) + + For LLC encapsulated VCCs (BLLI Layer 2 Protocol == T_ATM_BLLI2_I8802), + HARP has implemented an LLC multiplexing facility. In order to use this + multiplexing facility, a user must issue a setsockopt() call specifying the + T_ATM_LLC option before the connect() or listen() system call is invoked. + + If using the LLC multiplexor, the user will only receive PDUs which match + the LLC header information specified in the socket option. The kernel + multiplexing software will strip the LLC header from all inbound PDUs and + add the specified LLC header to all outgoing PDUs - the user will never see + the LLC header. + + For listening sockets, the listener will be notified for all incoming LLC + calls (which also meet the other incoming call distribution selection + criteria), since the LLC header information is only carried in the data + PDUs, not in the signalling protocol. + + The T_ATM_LLC_SHARING flag is used to denote whether this user wishes to + share the VCC with other LLC users requesting similar connection attributes + to the same destination. + +o Application Name socket option (T_ATM_APP_NAME) + + This option is used to associate an identifier string (typically, the + application's name) with an open ATM socket. Currently, it is only used + for the "Owner" field in the output of the 'atm show vcc' command. If this + option is not set, then the "Owner" field will default to "(AAL5)". + + See the sample application below for an example of the use of this option. + +o PVC support + + The XNS document specifically does not provide support for ATM PVCs. + However, due in part to internal HARP requirements (the ILMI daemon), PVC + sockets are supported under the HARP implementation. + + To support PVC sockets, there is a new address format (T_ATM_PVC_ADDR) and + address definition (Atm_addr_pvc). Since there is no actual signalling + involved in setting up a PVC, a PVC socket connection only defines the + local socket-to-pvc connection - the remainder of the virtual circuit through + the ATM network to the remote endpoint must be defined independent of the + local socket creation. PVC socket connections are only allowed via the + connect() system call - listen()/accept() sockets cannot be supported. + Also, since there are no circuit parameters signalled, most of the + setsockopt() options are silently ignored. + +o SPANS support + + HARP has added ATM socket support for the FORE-proprietary SPANS address + format (T_ATM_SPANS_ADDR). A SPANS socket can only be established over + an ATM physical interface which is using the SPANS signalling manager. + There is limited ATM socket option support - the socket options can be set, + but most are silently ignored, since they are not applicable to the SPANS + protocols. The SPANS socket address support has not been thoroughly tested. + +o Miscellaneous user convenience typedefs, macros and defines + + +XNS Issue 5 Features Not Supported in HARP +------------------------------------------ +o ATM_PROTO_SSCOP + + The socket protocol for reliable data transport (ATM_PROTO_SSCOP) is not + supported in this HARP release. There is some initial skeleton code for + SSCOP support, but it was not completed. + +o Multipoint connections + + The core HARP code does not provide support for multipoint connections, so, + obviously, multipoint socket connections are also not supported. + + The non-supported socket options are: + o T_ATM_ADD_LEAF + o T_ATM_DROP_LEAF + o T_ATM_LEAF_IND + + The non-supported socket option values are: + o For the T_ATM_BEARER_CAP socket option: + o connection_configuration == T_ATM_1_TO_MANY + + +Example ATM Socket Application +------------------------------ +The following is a simple example application using the ATM socket API. + +/* + * ATM API sample application + * + * This application will open an ATM socket, send a text string in a PDU + * and then read one PDU from the socket and print its contents. + * + */ +#include <sys/param.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netatm/atm.h> + +#define MAX_LEN 4096 /* Maximum PDU length */ +#define MY_ID 11 /* BLLI Layer 2 protocol */ +#define MY_APPL "SAMPLE" + +Atm_addr_nsap dst_addr = { + 0x47, + {0x00,0x05,0x80,0xff,0xdc,0x00,0x00,0x00,0x00,0x02,0xff,0xff}, + {0x11,0x22,0x33,0x44,0x55,0x66}, + 0x00 +}; + +static char message[] = "Test message to send on connection"; + + +main(argc, argv) + int argc; + char **argv; +{ + struct sockaddr_atm satm; + struct t_atm_aal5 aal5; + struct t_atm_traffic traffic; + struct t_atm_bearer bearer; + struct t_atm_qos qos; + struct t_atm_net_intf netintf; + struct t_atm_app_name appname; + char buffer[MAX_LEN+1]; + int s, n, optlen; + + /* + * Create socket + */ + s = socket(AF_ATM, SOCK_SEQPACKET, ATM_PROTO_AAL5); + if (s < 0) { + perror("socket"); + exit(1); + } + + /* + * Set up destination SAP + */ + bzero((caddr_t) &satm, sizeof(satm)); + satm.satm_family = AF_ATM; +#if (defined(BSD) && (BSD >= 199103)) + satm.satm_len = sizeof(satm); +#endif + /* Destination ATM address */ + satm.satm_addr.t_atm_sap_addr.SVE_tag_addr = T_ATM_PRESENT; + satm.satm_addr.t_atm_sap_addr.SVE_tag_selector = T_ATM_PRESENT; + satm.satm_addr.t_atm_sap_addr.address_format = T_ATM_ENDSYS_ADDR; + satm.satm_addr.t_atm_sap_addr.address_length = sizeof(Atm_addr_nsap); + bcopy((caddr_t)&dst_addr, + (caddr_t)satm.satm_addr.t_atm_sap_addr.address, + sizeof(dst_addr)); + + /* BLLI Layer-2 protocol */ + satm.satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_PRESENT; + satm.satm_addr.t_atm_sap_layer2.ID_type = T_ATM_USER_ID; + satm.satm_addr.t_atm_sap_layer2.ID.user_defined_ID = MY_ID; + + /* BLLI Layer-3 protocol */ + satm.satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT; + + /* BHLI protocol */ + satm.satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT; + + /* + * Set up connection parameters + */ + aal5.forward_max_SDU_size = MAX_LEN; + aal5.backward_max_SDU_size = MAX_LEN; + aal5.SSCS_type = T_ATM_NULL; + optlen = sizeof(aal5); + if (setsockopt(s, T_ATM_SIGNALING, T_ATM_AAL5, (caddr_t)&aal5, + optlen) < 0) { + perror("setsockopt(aal5)"); + exit(1); + } + + traffic.forward.PCR_high_priority = T_ATM_ABSENT; + traffic.forward.PCR_all_traffic = 100000; + traffic.forward.SCR_high_priority = T_ATM_ABSENT; + traffic.forward.SCR_all_traffic = T_ATM_ABSENT; + traffic.forward.MBS_high_priority = T_ATM_ABSENT; + traffic.forward.MBS_all_traffic = T_ATM_ABSENT; + traffic.forward.tagging = T_NO; + traffic.backward.PCR_high_priority = T_ATM_ABSENT; + traffic.backward.PCR_all_traffic = 100000; + traffic.backward.SCR_high_priority = T_ATM_ABSENT; + traffic.backward.SCR_all_traffic = T_ATM_ABSENT; + traffic.backward.MBS_high_priority = T_ATM_ABSENT; + traffic.backward.MBS_all_traffic = T_ATM_ABSENT; + traffic.backward.tagging = T_NO; + traffic.best_effort = T_YES; + optlen = sizeof(traffic); + if (setsockopt(s, T_ATM_SIGNALING, T_ATM_TRAFFIC, (caddr_t)&traffic, + optlen) < 0) { + perror("setsockopt(traffic)"); + exit(1); + } + + bearer.bearer_class = T_ATM_CLASS_X; + bearer.traffic_type = T_ATM_NULL; + bearer.timing_requirements = T_ATM_NULL; + bearer.clipping_susceptibility = T_NO; + bearer.connection_configuration = T_ATM_1_TO_1; + optlen = sizeof(bearer); + if (setsockopt(s, T_ATM_SIGNALING, T_ATM_BEARER_CAP, (caddr_t)&bearer, + optlen) < 0) { + perror("setsockopt(bearer)"); + exit(1); + } + + qos.coding_standard = T_ATM_NETWORK_CODING; + qos.forward.qos_class = T_ATM_QOS_CLASS_0; + qos.backward.qos_class = T_ATM_QOS_CLASS_0; + optlen = sizeof(qos); + if (setsockopt(s, T_ATM_SIGNALING, T_ATM_QOS, (caddr_t)&qos, + optlen) < 0) { + perror("setsockopt(qos)"); + exit(1); + } + + strncpy(netintf.net_intf, "ni0", IFNAMSIZ); + optlen = sizeof(netintf); + if (setsockopt(s, T_ATM_SIGNALING, T_ATM_NET_INTF, (caddr_t)&netintf, + optlen) < 0) { + perror("setsockopt(net_intf)"); + exit(1); + } + + strncpy(appname.app_name, MY_APPL, T_ATM_APP_NAME_LEN); + optlen = sizeof(appname); + if (setsockopt(s, T_ATM_SIGNALING, T_ATM_APP_NAME, (caddr_t)&appname, + optlen) < 0) { + perror("setsockopt(app_name)"); + exit(1); + } + + /* + * Now try to connect to destination + */ + if (connect(s, (struct sockaddr *) &satm, sizeof(satm)) < 0) { + perror("connect"); + exit(1); + } + + /* + * Exchange message with peer + */ + if (write(s, message, sizeof(message)) != sizeof(message)) { + perror("write"); + exit(1); + } + + if ((n = read(s, buffer, MAX_LEN) < 0)) { + perror("read"); + exit(1); + } + + buffer[n] = '\0'; + printf("received %d bytes: <%s>\n", n, buffer); + + /* + * Finish up + */ + if (close(s) < 0) { + perror("close"); + exit(1); + } + + exit(0); +} + + @(#) $Id: atm_sockets,v 1.1 1998/08/26 21:52:01 mks Exp $ + diff --git a/share/examples/atm/cpcs-design.txt b/share/examples/atm/cpcs-design.txt new file mode 100644 index 0000000..aecfa81 --- /dev/null +++ b/share/examples/atm/cpcs-design.txt @@ -0,0 +1,84 @@ + + CPCS Design + =========== + +SAP_CPCS Interface +------------------ +This is the stack SAP interface between an AAL CPCS provider and an AAL CPCS +user. The stack commands defined for this interface are modeled after the +AAL3/4 and AAL5 protocol specification primitives CPCS-xxx. See the protocol +specification documents referenced below for full descriptions of the CPCS +interface. + + +o The following stack commands are sent from a CPCS user to the CPCS provider: + +Stack Command: CPCS_INIT +Description: Initialize a SAP instance. This should be the first stack + command issued across the SAP instance after the service stack + has been successfully instantiated. +Argument 1: Not used. +Argument 2: Not used. + + +Stack Command: CPCS_TERM +Description: Terminate a SAP instance. This must be the last stack command + issued across the SAP instance. The stack instance will be + deleted upon completion of this command. +Argument 1: Not used. +Argument 2: Not used. + + +Stack Command: CPCS_UNITDATA_INV +Description: Request that an SDU be sent to the remote AAL user. +Argument 1: Pointer to an mbuf chain containing the user SDU. + (struct mbuf *) +Argument 2: Not used. + + +Stack Command: CPCS_UABORT_INV +Description: Not supported. +Argument 1: N/A +Argument 2: N/A + + +o The following stack commands are sent from the CPCS provider to a CPCS user: + +Stack Command: CPCS_UNITDATA_SIG +Description: Indication that an SDU has been received from the remote AAL + user. +Argument 1: Pointer to an mbuf chain containing the peer's SDU. + (struct mbuf *) +Argument 2: Not used. + + +Stack Command: CPCS_UABORT_SIG +Description: Not supported. +Argument 1: N/A +Argument 2: N/A + + +Stack Command: CPCS_PABORT_SIG +Description: Not supported. +Argument 1: N/A +Argument 2: N/A + + + +Protocol Specifications +----------------------- +See I.363. + + + +Implementation Limitations +-------------------------- +o The CPCS-LP, CPCS-CI and CPCS-UU parameters are not supported. + +o The Streaming Mode service is not supported. + +o The Abort service is not supported. + + + @(#) $Id: cpcs.design,v 1.1.1.1 1996/12/04 20:48:14 mks Exp $ + diff --git a/share/examples/atm/fore-microcode.txt b/share/examples/atm/fore-microcode.txt new file mode 100644 index 0000000..ab1e16d --- /dev/null +++ b/share/examples/atm/fore-microcode.txt @@ -0,0 +1,92 @@ + +HARP and FORE Systems Microcode +=============================== + +ATM adapters from FORE Systems use Intel i960 embedded processors and +require that application software (herein called "microcode") be downloaded +and executed on the adapter. The interface between the microcode and the host +device driver is specified in the FORE ATM Adaptation Layer Interface (AALI) +(available from ftp.fore.com:/pub/docs/port). HARP uses microcode supplied +by FORE Systems. The HARP device driver for the FORE adapter (hfa) conforms +to the AALI specification. + +As part of the HARP ATM initialization procedure, the HARP 'fore_dnld' utility +must be invoked in order to load the microcode file into each FORE adapter. +However, the microcode file is NOT included in the FreeBSD distribution. It is +the user's responsibilty to obtain and install the FORE microcode file. Below +are notes to assist users in finding and installing microcode known to work +with HARP. + +FORE microcode files can be obtained from either FORE's web site +(http://www.fore.com) or the CD distributed with new FORE adapters. +When using FORE's web site, you must have a valid login to access the +TACtics Online section of the site. The software download section is +available via the 'Services & Support'->'TACtics Online'->Software links. + +If you are currently using HARP and already have a working microcode file, +that microcode will continue to work with this release of HARP. + + +PCA200E +------- + +From the FORE web pages, the following PCA200E adapter distributions +are known to have microcode which will work with HARP: + + pc_adapter->OS/2->archive->os2_4.0.2_1.20.200.zip + unzip the file and execute the command: + + cp -p <unzip_directory>/Drivers/PCA200E.BIN /etc/pca200e.bin + + pc_adapter->'Windows NT'->archive->pca2e_12.zip + unzip the file and execute the command: + + cp -p <unzip_directory>/NT/I386/PCA200E.BIN /etc/pca200e.bin + + +The following distributions from the FORE web pages are known to have +microcode which will NOT work with HARP: + + pc_adapter: + OS/2: + release: + os2_4.1.0_1.74.zip + Windows95: + archive: + pc-w95_5.0.0.16432.zip + win95_4.0.3_1.04.200.zip + win95_4.1.6_1.16.zip + release: + pc-w95_4.1.6_27.zip + Windows NT: + archive: + pc-nt_5.0.0_16342.zip + winnt_4.0.3_1.05.200.zip + winnt_4.1.2_1.27.zip + winnt_4.1.6_1.16.zip + release: + pc-nt_4.1.6_27.zip + pc-nt_i386_5.0.0_25096.zip + + +From the "ForeRunner 200E for PC/Mac" distribution CD-ROM, the following +PCA200E adapter distributions are known to have microcode which will work +with HARP (assuming the CD-ROM is mounted on /cdrom): + + /cdrom/rel4.0/os2/ + execute the command: + + cp -p /cdrom/rel4.0/os2/drivers/pca200e.bin /etc/pca200e.bin + + +Note: Windows-based files are supplied in a compressed form. If the +'fore_dnld' command complains about an unrecognized header format, you should +try to uncompress the microcode file. To do so, move the file in binary mode +to a DOS/Windows machine and use the DOS command 'expand' to uncompress the +file. The command syntax is: + + expand <in-file> <out-file> + +Move the resulting <out-file> in binary mode back to the HARP machine as +/etc/pca200e.bin and try to initialize the ATM system again. + diff --git a/share/examples/atm/sscf-design.txt b/share/examples/atm/sscf-design.txt new file mode 100644 index 0000000..a6e3f9e --- /dev/null +++ b/share/examples/atm/sscf-design.txt @@ -0,0 +1,129 @@ + + SSCF UNI Design + =============== + +SAP_SSCF_UNI Interface +---------------------- +This is the stack SAP interface between the UNI signalling layer (eg. Q.2931) +and the SSCF module. The stack commands defined for this interface are modeled +after the SSCF protocol specification primitives AAL-xxx. See the protocol +specification documents referenced below for full descriptions of the SSCF UNI +interface presented to the signalling user. + + +o The following stack commands are sent from the signalling module to SSCF: + +Stack Command: SSCF_UNI_INIT +Description: Initialize a SAP instance. This should be the first stack + command issued across the SAP instance after the service stack + has been successfully instantiated. +Argument 1: Specifies the UNI version to be used for this stack instance. + (enum uni_vers) +Argument 2: Not used. + + +Stack Command: SSCF_UNI_TERM +Description: Terminate a SAP instance. This must be the last stack command + issued across the SAP instance. The stack instance will be + deleted upon completion of this command. +Argument 1: Not used. +Argument 2: Not used. + + +Stack Command: SSCF_UNI_ESTABLISH_REQ +Description: Request the establishment of an assured SAAL connection to the + SAAL peer entity. +Argument 1: Not used. +Argument 2: Not used. + + +Stack Command: SSCF_UNI_RELEASE_REQ +Description: Request the termination of an assured SAAL connection to the + SAAL peer entity. +Argument 1: Specifies whether future session establishment indications from + the SAAL peer should be processed. Valid values are + SSCF_UNI_ESTIND_YES or SSCF_UNI_ESTIND_NO. (int) + Note that this is a local implementation parameter only. +Argument 2: Not used. + + +Stack Command: SSCF_UNI_DATA_REQ +Description: Request that an assured SDU be sent to the SAAL peer. +Argument 1: Pointer to an mbuf chain containing the user SDU. + (struct mbuf *) +Argument 2: Not used. + + +Stack Command: SSCF_UNI_UNITDATA_REQ +Description: Request that an unacknowledged SDU be sent to the SAAL peer. +Argument 1: Pointer to an mbuf chain containing the user SDU. + (struct mbuf *) +Argument 2: Not used. + + +o The following stack commands are sent from SSCF to the signalling module: + +Stack Command: SSCF_UNI_ESTABLISH_IND +Description: Indication that an assured SAAL connection has been established + by the SAAL peer entity. +Argument 1: Not used. +Argument 2: Not used. + + +Stack Command: SSCF_UNI_ESTABLISH_CNF +Description: Confirmation of an assured SAAL connection establishment, + previously requested via an SSCF_UNI_ESTABLISH_REQ command. +Argument 1: Not used. +Argument 2: Not used. + + +Stack Command: SSCF_UNI_RELEASE_IND +Description: Indication that an assured SAAL connection has been terminated + by the SAAL peer entity. +Argument 1: Not used. +Argument 2: Not used. + + +Stack Command: SSCF_UNI_RELEASE_CNF +Description: Confirmation of an assured SAAL connection termination, + previously requested via an SSCF_UNI_RELEASE_REQ command. +Argument 1: Not used. +Argument 2: Not used. + + +Stack Command: SSCF_UNI_DATA_IND +Description: Indication that an assured SDU has been received from the + SAAL peer. +Argument 1: Pointer to an mbuf chain containing the peer's SDU. + (struct mbuf *) +Argument 2: Not used. + + +Stack Command: SSCF_UNI_UNITDATA_IND +Description: Indication that an unacknowledged SDU has been received from + the SAAL peer. +Argument 1: Pointer to an mbuf chain containing the peer's SDU. + (struct mbuf *) +Argument 2: Not used. + + + +Protocol Specifications +----------------------- +For UNI_VERS_3_0, see Q.SAAL2. +For UNI_VERS_3_1, see Q.2130. + + + +Implementation Limitations +-------------------------- +o The Parameter Data parameter is not supported for the following primitives: + AAL-ESTABLISH request + AAL-ESTABLISH indication + AAL-ESTABLISH confirm + AAL-RELEASE request + AAL-RELEASE indication + + + @(#) $Id: sscf.design,v 1.1.1.1 1996/12/04 20:48:17 mks Exp $ + diff --git a/share/examples/atm/sscop-design.txt b/share/examples/atm/sscop-design.txt new file mode 100644 index 0000000..009f242 --- /dev/null +++ b/share/examples/atm/sscop-design.txt @@ -0,0 +1,220 @@ + + SSCOP Design + ============ + +SAP_SSCOP Interface +------------------- +This is the stack SAP interface between the SSCOP module and an SSCOP user +module (eg. SSCF). The stack commands defined for this interface are modeled +after the SSCOP protocol specification primitives AA-xxx. See the protocol +specification documents referenced below for full descriptions of the SSCOP +interface presented to an SSCF. + + +o The following stack commands are sent from an SSCF to SSCOP: + +Stack Command: SSCOP_INIT +Description: Initialize a SAP instance. This should be the first stack + command issued across the SAP instance after the service stack + has been successfully instantiated. +Argument 1: Specifies the SSCOP version to be used for this stack instance. + (enum sscop_vers) +Argument 2: Pointer to a structure containing the SSCOP protocol parameter + values to be used for this instance. (struct sscop_parms *) + + +Stack Command: SSCOP_TERM +Description: Terminate a SAP instance. This must be the last stack command + issued across the SAP instance. The stack instance will be + deleted upon completion of this command. +Argument 1: Not used. +Argument 2: Not used. + + +Stack Command: SSCOP_ESTABLISH_REQ +Description: Request the establishment of an SSCOP connection for assured + information transfer to the remote peer entity. +Argument 1: Pointer to an mbuf chain containing any SSCOP User-to-User + Information (SSCOP-UU / UUI) data to be sent to the peer. + Must be coded as SSCOP_UU_NULL. (struct mbuf *) +Argument 2: Buffer Release (BR) parameter. Must be coded as SSCOP_BR_YES. + (int) + + +Stack Command: SSCOP_ESTABLISH_RSP +Description: Response indicating that an SSCOP connection establishment + request from the remote peer is acceptable. +Argument 1: Pointer to an mbuf chain containing any SSCOP User-to-User + Information (SSCOP-UU / UUI) data to be sent to the peer. + Must be coded as SSCOP_UU_NULL. (struct mbuf *) +Argument 2: Buffer Release (BR) parameter. Must be coded as SSCOP_BR_YES. + (int) + + +Stack Command: SSCOP_RELEASE_REQ +Description: Request the termination of an SSCOP connection with the + remote peer entity. +Argument 1: Pointer to an mbuf chain containing any SSCOP User-to-User + Information (SSCOP-UU / UUI) data to be sent to the peer. + Must be coded as SSCOP_UU_NULL. (struct mbuf *) +Argument 2: Not used. + + +Stack Command: SSCOP_DATA_REQ +Description: Request that an assured SDU be sent to the remote peer. +Argument 1: Pointer to an mbuf chain containing the user SDU. + (struct mbuf *) +Argument 2: Not used. + + +Stack Command: SSCOP_RESYNC_REQ +Description: Request the resynchronization of an SSCOP connection. +Argument 1: Pointer to an mbuf chain containing any SSCOP User-to-User + Information (SSCOP-UU / UUI) data to be sent to the peer. + Must be coded as SSCOP_UU_NULL. (struct mbuf *) +Argument 2: Not used. + + +Stack Command: SSCOP_RESYNC_RSP +Description: Acknowledge the remote peer's resynchronization of an SSCOP + connection. +Argument 1: Not used. +Argument 2: Not used. + + +Stack Command: SSCOP_RECOVER_RSP (Q.2110 only) +Description: Acknowledge the indication that the SSCOP connection has + recovered from SSCOP protocol errors. +Argument 1: Not used. +Argument 2: Not used. + + +Stack Command: SSCOP_UNITDATA_REQ +Description: Request that an unacknowledged SDU be sent to the remote peer. +Argument 1: Pointer to an mbuf chain containing the user SDU. + (struct mbuf *) +Argument 2: Not used. + + +Stack Command: SSCOP_RETRIEVE_REQ +Description: Not supported. +Argument 1: N/A +Argument 2: N/A + + +o The following stack commands are sent from SSCOP to an SSCF: + +Stack Command: SSCOP_ESTABLISH_IND +Description: Indication that a request to establish an SSCOP connection has + been received from the remote peer entity. +Argument 1: Pointer to an mbuf chain containing any SSCOP User-to-User + Information (SSCOP-UU / UUI) data received from the peer. + (struct mbuf *) +Argument 2: Source of establish request (Q.SAAL1 only). Valid values are + SSCOP_SOURCE_SSCOP or SSCOP_SOURCE_USER. (int) + + +Stack Command: SSCOP_ESTABLISH_CNF +Description: Confirmation from the remote peer of an SSCOP connection + establishment, previously requested via an SSCOP_ESTABLISH_REQ + command. +Argument 1: Pointer to an mbuf chain containing any SSCOP User-to-User + Information (SSCOP-UU / UUI) data received from the peer. + (struct mbuf *) +Argument 2: Not used. + + +Stack Command: SSCOP_RELEASE_IND +Description: Indication that an SSCOP connection has been terminated by + the remote peer entity. +Argument 1: Pointer to an mbuf chain containing any SSCOP User-to-User + Information (SSCOP-UU / UUI) data received from the peer. + (struct mbuf *) +Argument 2: Source of release request. Valid values are SSCOP_SOURCE_SSCOP + or SSCOP_SOURCE_USER. (int) + + +Stack Command: SSCOP_RELEASE_CNF +Description: Confirmation from the remote peer of an SSCOP connection + termination, previously requested via an SSCOP_RELEASE_REQ + command. +Argument 1: Not used. +Argument 2: Not used. + + +Stack Command: SSCOP_DATA_IND +Description: Indication that an assured SDU has been received from the + remote peer. +Argument 1: Pointer to an mbuf chain containing the peer's SDU. + (struct mbuf *) +Argument 2: Sequence number of the received SDU. (sscop_seq) + + +Stack Command: SSCOP_RESYNC_IND +Description: Indication that the remote peer has requested the + resynchronization of the SSCOP connection. +Argument 1: Pointer to an mbuf chain containing any SSCOP User-to-User + Information (SSCOP-UU / UUI) data received from the peer. + (struct mbuf *) +Argument 2: Not used. + + +Stack Command: SSCOP_RESYNC_CNF +Description: Confirmation from the remote peer that an SSCOP connection + has been resynchronized. +Argument 1: Not used. +Argument 2: Not used. + + +Stack Command: SSCOP_RECOVER_IND (Q.2110 only) +Description: Indication that an SSCOP connection has recovered from SSCOP + protocol errors. +Argument 1: Not used. +Argument 2: Not used. + + +Stack Command: SSCOP_UNITDATA_IND +Description: Indication that an unacknowledged SDU has been received from + the remote peer. +Argument 1: Pointer to an mbuf chain containing the peer's SDU. + (struct mbuf *) +Argument 2: Not used. + + +Stack Command: SSCOP_RETRIEVE_IND +Description: Not supported. +Argument 1: N/A +Argument 2: N/A + + +Stack Command: SSCOP_RETRIEVECMP_IND +Description: Not supported. +Argument 1: N/A +Argument 2: N/A + + + +Protocol Specifications +----------------------- +For SSCOP_VERS_QSAAL, see Q.SAAL1. +For SSCOP_VERS_Q2110, see Q.2110. + + + +Implementation Limitations +-------------------------- +o The following signals are not supported: + AA-RETRIEVE + AA-RETRIEVE COMPLETE + AA-RELEASEBUF (Q.SAAL1 only) + MAA-UNITDATA + +o Does not support sending the SSCOP-UU/UUI parameter, must be set to NULL + +o For the AA-ESTABLISH request and response signals, only BR=YES is supported + +o For the AA-DATA request signal, only PR=NO is supported (Q.SAAL1 only) + + + @(#) $Id: sscop.design,v 1.1.1.1 1996/12/04 20:48:17 mks Exp $ + diff --git a/sys/dev/hea/eni.c b/sys/dev/hea/eni.c new file mode 100644 index 0000000..088503a --- /dev/null +++ b/sys/dev/hea/eni.c @@ -0,0 +1,664 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: eni.c,v 1.4 1998/06/29 19:39:10 jpt Exp $ + * + */ + +/* + * Efficient ENI adapter support + * ----------------------------- + * + * Module supports PCI interface to ENI adapter + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: eni.c,v 1.4 1998/06/29 19:39:10 jpt Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <dev/hea/eni_stats.h> +#include <dev/hea/eni.h> +#include <dev/hea/eni_var.h> + +/* + * Typedef local functions + */ +static char *eni_pci_probe __P((pcici_t, pcidi_t)); +static void eni_pci_attach __P((pcici_t, int)); +static int eni_get_ack __P((Eni_unit *)); +static int eni_get_sebyte __P((Eni_unit *)); +static void eni_read_seeprom __P((Eni_unit *)); +#ifdef __FreeBSD__ +#if BSD < 199506 +static int eni_pci_shutdown __P((struct kern_devconf *, int)); +#else +static void eni_pci_shutdown __P((int, void *)); +#endif +static void eni_pci_reset __P((Eni_unit *)); +#endif /* __FreeBSD__ */ + +/* + * Used by kernel to return number of claimed devices + */ +#ifdef __FreeBSD__ +static u_long eni_nunits; + +static struct pci_device eni_pci_device = { + ENI_DEV_NAME, + eni_pci_probe, + eni_pci_attach, + &eni_nunits, +#if BSD < 199506 + eni_pci_shutdown +#else + NULL +#endif +}; + +DATA_SET ( pcidevice_set, eni_pci_device ); +#endif /* __FreeBSD__ */ + +/* + * Called by kernel with PCI device_id which was read from the PCI + * register set. If the identified vendor is Efficient, see if we + * recognize the particular device. If so, return an identifying string, + * if not, return null. + * + * Arguments: + * config_id PCI config token + * device_id contents of PCI device ID register + * + * Returns: + * string Identifying string if we will handle this device + * NULL unrecognized vendor/device + * + */ +static char * +eni_pci_probe ( pcici_t config_id, pcidi_t device_id ) +{ + + if ( (device_id & 0xFFFF) == EFF_VENDOR_ID ) { + switch ( (device_id >> 16) ) { + case EFF_DEV_ID: + return ( "Efficient ENI ATM Adapter" ); +/* NOTREACHED */ + break; + } + } + + return ( NULL ); +} + +/* + * The ENI-155p adapter uses an ATMEL AT24C01 serial EEPROM to store + * configuration information. The SEEPROM is accessed via two wires, + * CLOCK and DATA, which are accessible via the PCI configuration + * registers. The following macros manipulate the lines to access the + * SEEPROM. See http://www.atmel.com/atmel/products/prod162.htm for + * a description of the AT24C01 part. Value to be read/written is + * part of the per unit structure. + */ +/* + * Write bits to SEEPROM + */ +#define WRITE_SEEPROM() ( \ + { \ + (void) pci_conf_write ( eup->eu_pcitag, SEEPROM, \ + eup->eu_sevar ); \ + DELAY(SEPROM_DELAY); \ + } \ +) +/* + * Stobe first the DATA, then the CLK lines high + */ +#define STROBE_HIGH() ( \ + { \ + eup->eu_sevar |= SEPROM_DATA; WRITE_SEEPROM(); \ + eup->eu_sevar |= SEPROM_CLK; WRITE_SEEPROM(); \ + } \ +) +/* + * Strobe first the CLK, then the DATA lines high + */ +#define INV_STROBE_HIGH() ( \ + { \ + eup->eu_sevar |= SEPROM_CLK; WRITE_SEEPROM(); \ + eup->eu_sevar |= SEPROM_DATA; WRITE_SEEPROM(); \ + } \ +) +/* + * Strobe first the CLK, then the DATA lines low - companion to + * STROBE_HIGH() + */ +#define STROBE_LOW() ( \ + { \ + eup->eu_sevar &= ~SEPROM_CLK; WRITE_SEEPROM(); \ + eup->eu_sevar &= ~SEPROM_DATA; WRITE_SEEPROM(); \ + } \ +) +/* + * Strobe first the DATA, then the CLK lines low - companion to + * INV_STROBE_HIGH() + */ +#define INV_STROBE_LOW() ( \ + { \ + eup->eu_sevar &= ~SEPROM_DATA; WRITE_SEEPROM(); \ + eup->eu_sevar &= ~SEPROM_CLK; WRITE_SEEPROM(); \ + } \ +) +/* + * Strobe the CLK line high, then low + */ +#define STROBE_CLK() ( \ + { \ + eup->eu_sevar |= SEPROM_CLK; WRITE_SEEPROM(); \ + eup->eu_sevar &= ~SEPROM_CLK; WRITE_SEEPROM(); \ + } \ +) + +/* + * Look for a positive ACK from the SEEPROM. Cycle begins by asserting + * the DATA line, then the CLK line. The DATA line is then read to + * retrieve the ACK status, and then the cycle is finished by deasserting + * the CLK line, and asserting the DATA line. + * + * Arguments: + * eup pointer to per unit structure + * + * Returns: + * 0/1 value of ACK + * + */ +static int +eni_get_ack ( eup ) + Eni_unit *eup; +{ + int ack; + + STROBE_HIGH(); + /* + * Read DATA line from SEPROM + */ + eup->eu_sevar = pci_conf_read ( eup->eu_pcitag, SEEPROM ); + DELAY ( SEPROM_DELAY ); + ack = eup->eu_sevar & SEPROM_DATA; + + eup->eu_sevar &= ~SEPROM_CLK; + WRITE_SEEPROM (); + eup->eu_sevar |= SEPROM_DATA; + WRITE_SEEPROM (); + + return ( ack ); +} + +/* + * Read a byte from the SEEPROM. Data is read as 8 bits. There are two types + * of read operations. The first is a single byte read, the second is + * multiple sequential bytes read. Both cycles begin with a 'START' operation, + * followed by a memory address word. Following the memory address, the + * SEEPROM will send a data byte, followed by an ACK. If the host responds + * with a 'STOP' operation, then a single byte cycle is performed. If the + * host responds with an 'ACK', then the memory address is incremented, and + * the next sequential memory byte is serialized. + * + * Arguments: + * eup pointer to per unit structure + * + * Returns: + * val value of byte read from SEEPROM + * + */ +static int +eni_get_sebyte( eup ) + Eni_unit *eup; +{ + int i; + int data; + int rval; + + /* Initial value */ + rval = 0; + /* Read 8 bits */ + for ( i = 0; i < 8; i++ ) { + /* Shift bits to left so the next bit goes to position 0 */ + rval <<= 1; + /* Indicate we're ready to read bit */ + STROBE_HIGH(); + /* + * Read DATA line from SEPROM + */ + data = pci_conf_read ( eup->eu_pcitag, SEEPROM ); + DELAY ( SEPROM_DELAY ); + /* (Possibly) mask bit into accumulating value */ + if ( data & SEPROM_DATA ) + rval |= 1; /* If DATA bit '1' */ + /* Indicate we're done reading this bit */ + STROBE_LOW(); + } + + /* Return acquired byte */ + return ( rval ); +} + +/* + * The AT24C01 is a 1024 bit part organized as 128 words by 8 bits. + * We will read the entire contents into the per unit structure. Later, + * we'll retrieve the MAC address and serial number from the data read. + * + * Arguments: + * eup pointer to per unit structure + * + * Returns: + * none + * + */ +static void +eni_read_seeprom ( eup ) + Eni_unit *eup; +{ + int addr; + int i, j; + + /* + * Set initial state + */ + eup->eu_sevar = SEPROM_DATA | SEPROM_CLK; + WRITE_SEEPROM (); + + /* Loop for all bytes */ + for ( i = 0; i < SEPROM_SIZE ; i++ ) { + /* Send START operation */ + STROBE_HIGH(); + INV_STROBE_LOW(); + + /* + * Send address. Addresses are sent as 7 bits plus + * last bit high. + */ + addr = ((i) << 1) + 1; + /* + * Start with high order bit first working toward low + * order bit. + */ + for ( j = 7; j >= 0; j-- ) { + /* Set current bit value */ + eup->eu_sevar = ( addr >> j ) & 1 ? + eup->eu_sevar | SEPROM_DATA : + eup->eu_sevar & ~SEPROM_DATA; + WRITE_SEEPROM (); + /* Indicate we've sent it */ + STROBE_CLK(); + } + /* + * We expect a zero ACK after sending the address + */ + if ( !eni_get_ack ( eup ) ) { + /* Address okay - read data byte */ + eup->eu_seeprom[i] = eni_get_sebyte ( eup ); + /* Grab but ignore the ACK op */ + (void) eni_get_ack ( eup ); + } else { + /* Address ACK was bad - can't retrieve data byte */ + eup->eu_seeprom[i] = 0xff; + } + } + + return; +} + +/* + * The kernel has found a device which we are willing to support. + * We are now being called to do any necessary work to make the + * device initially usable. In our case, this means allocating + * structure memory, configuring registers, mapping device + * memory, setting pointers, registering with the core services, + * and doing the initial PDU processing configuration. + * + * Arguments: + * config_id PCI device token + * unit instance of the unit + * + * Returns: + * none + * + */ +static void +eni_pci_attach ( pcici_t config_id, int unit ) +{ + vm_offset_t va; + vm_offset_t pa; + Eni_unit *eup; + long val; + + /* + * Just checking... + */ + if ( unit >= ENI_MAX_UNITS ) { + log ( LOG_ERR, "%s%d: too many devices\n", + ENI_DEV_NAME, unit ); + return; + } + + /* + * Make sure this isn't a duplicate unit + */ + if ( eni_units[unit] != NULL ) + return; + + /* + * Allocate a new unit structure + */ + eup = (Eni_unit *) atm_dev_alloc ( sizeof(Eni_unit), sizeof(int), 0 ); + if ( eup == NULL ) + return; + + /* + * Start initializing it + */ + eup->eu_unit = unit; + eup->eu_mtu = ENI_IFF_MTU; + eup->eu_pcitag = config_id; + eup->eu_ioctl = eni_atm_ioctl; + eup->eu_instvcc = eni_instvcc; + eup->eu_openvcc = eni_openvcc; + eup->eu_closevcc = eni_closevcc; + eup->eu_output = eni_output; + eup->eu_vcc_pool = &eni_vcc_pool; + eup->eu_nif_pool = &eni_nif_pool; + + /* + * Map in adapter RAM + */ + if ( ( pci_map_mem ( config_id, PCI_MAP_REG_START, &va, &pa ) ) == 0 ) + { + /* + * Nothing's happened yet that we need to undo. + */ + return; + } + /* + * Map okay - retain address assigned + */ + eup->eu_base = (Eni_mem)va; + eup->eu_ram = (Eni_mem)(eup->eu_base + RAM_OFFSET); + + /* + * Map memory structures into adapter space + */ + eup->eu_suni = (Eni_mem)(eup->eu_base + SUNI_OFFSET); + eup->eu_midway = (Eni_mem)(eup->eu_base + MIDWAY_OFFSET); + eup->eu_vcitbl = (VCI_Table *)(eup->eu_base + VCITBL_OFFSET); + eup->eu_rxdma = (Eni_mem)(eup->eu_base + RXQUEUE_OFFSET); + eup->eu_txdma = (Eni_mem)(eup->eu_base + TXQUEUE_OFFSET); + eup->eu_svclist = (Eni_mem)(eup->eu_base + SVCLIST_OFFSET); + eup->eu_servread = 0; + + /* + * Reset the midway chip + */ + eup->eu_midway[MIDWAY_ID] = MIDWAY_RESET; + + /* + * Size and test adapter memory. Initialize our adapter memory + * allocater. + */ + if ( eni_init_memory ( eup ) < 0 ) { + /* + * Adapter memory test failed. Clean up and + * return. + */ + /* + * FreeBSD doesn't support unmapping PCI memory (yet?). + */ + return; + } + + /* + * Read the contents of the SEEPROM + */ + eni_read_seeprom ( eup ); + /* + * Copy MAC address to PIF and config structures + */ + KM_COPY ( (caddr_t)&eup->eu_seeprom[SEPROM_MAC_OFF], + (caddr_t)&eup->eu_pif.pif_macaddr, sizeof(struct mac_addr) ); + eup->eu_config.ac_macaddr = eup->eu_pif.pif_macaddr; + + /* + * Copy serial number into config space + */ + eup->eu_config.ac_serial = + ntohl(*(u_long *)&eup->eu_seeprom[SEPROM_SN_OFF]); + + /* + * Convert Endianess on DMA + */ + val = pci_conf_read ( config_id, PCI_CONTROL_REG ); + val |= ENDIAN_SWAP_DMA; + pci_conf_write ( config_id, PCI_CONTROL_REG, val ); + + /* + * Map interrupt in + */ + if ( !pci_map_int ( config_id, eni_intr, (void *)eup, &net_imask ) ) + { + /* + * Finish by unmapping memory, etc. + */ + log ( LOG_ERR, "eni_pci_attach: Unable to map interrupt\n" ); + /* + * Can't unmap PCI memory (yet). + */ + return; + } + + /* + * Setup some of the adapter configuration + */ + /* + * Get MIDWAY ID + */ + val = eup->eu_midway[MIDWAY_ID]; + eup->eu_config.ac_vendor = VENDOR_ENI; + eup->eu_config.ac_vendapi = VENDAPI_ENI_1; + eup->eu_config.ac_device = DEV_ENI_155P; + eup->eu_config.ac_media = val & MEDIA_MASK ? MEDIA_UTP155 : MEDIA_OC3C; + eup->eu_pif.pif_pcr = ATM_PCR_OC3C; + eup->eu_config.ac_bustype = BUS_PCI; + eup->eu_config.ac_busslot = config_id->bus << 8 | config_id->slot; + + /* + * Make a hw version number from the ID register values. + * Format: {Midway ID}.{Mother board ID}.{Daughter board ID} + */ + sprintf ( eup->eu_config.ac_hard_vers, "%d/%d/%d", + (val >> ID_SHIFT) & ID_MASK, + (val >> MID_SHIFT) & MID_MASK, + (val >> DID_SHIFT) & DID_MASK ); + + /* + * There is no software version number + */ + sprintf ( eup->eu_config.ac_firm_vers, "\0" ); + + /* + * Save device ram info for user-level programs + * NOTE: This really points to start of EEPROM + * and includes all the device registers in the + * lower 2 Megabytes. + */ + eup->eu_config.ac_ram = (long)eup->eu_base; + eup->eu_config.ac_ramsize = eup->eu_ramsize + ENI_REG_SIZE; + + /* + * Setup max VPI/VCI values + */ + eup->eu_pif.pif_maxvpi = ENI_MAX_VPI; + eup->eu_pif.pif_maxvci = ENI_MAX_VCI; + + /* + * Register this interface with ATM core services + */ + if ( atm_physif_register + ( (Cmn_unit *)eup, ENI_DEV_NAME, eni_services ) != 0 ) + { + /* + * Registration failed - back everything out + */ + /* + * Can't unmap PCI memory (yet). + */ + /* + * Unmap PCI interrupt + */ + (void) pci_unmap_int ( config_id ); + log ( LOG_ERR, + "eni_pci_attach: atm_physif_register failed\n" ); + return; + } + + eni_units[unit] = eup; + +#if BSD >= 199506 + /* + * Add hook to out shutdown function + */ + at_shutdown ( (bootlist_fn)eni_pci_shutdown, eup, SHUTDOWN_POST_SYNC ); +#endif + + /* + * Initialize driver processing + */ + if ( eni_init ( eup ) ) { + log ( LOG_ERR, "eni_pci_attach: Failed eni_init()\n" ); + /* + * Can't unmap PCI memory (yet). + */ + /* + * Unmap PCI interrupt + */ + (void) pci_unmap_int ( config_id ); + /* + * Fall through to return + */ + } + + return; + +} + +/* + * Device reset routine + * + * Arguments: + * eup pointer to per unit structure + * + * Returns: + * none + * + */ +static void +eni_pci_reset ( eup ) + Eni_unit *eup; +{ + + /* + * We should really close down any open VCI's and + * release all memory (TX and RX) buffers. For now, + * we assume we're shutting the card down for good. + */ + + /* + * Issue RESET command to Midway chip + */ + eup->eu_midway[MIDWAY_ID] = MIDWAY_RESET; + + /* + * Delay to allow everything to terminate + */ + DELAY ( MIDWAY_DELAY ); + + return; +} + +#ifdef __FreeBSD__ +#if BSD < 199506 +/* + * Device shutdown routine + * + * Arguments: + * kdc pointer to device's configuration table + * force forced shutdown flag + * + * Returns: + * none + * + */ +static int +eni_pci_shutdown ( kdc, force ) + struct kern_devconf *kdc; + int force; +{ + Eni_unit *eup = NULL; + + if ( kdc->kdc_unit < eni_nunits ) { + + eup = eni_units[kdc->kdc_unit]; + if ( eup != NULL ) { + /* Do device reset */ + eni_pci_reset ( eup ); + } + } + + (void) dev_detach ( kdc ); + return ( 0 ); +} +#else +/* + * Device shutdown routine + * + * Arguments: + * howto type of shutdown + * eup pointer to device unit structure + * + * Returns: + * none + * + */ +static void +eni_pci_shutdown ( howto, eup ) + int howto; + void *eup; +{ + + /* Do device reset */ + eni_pci_reset ( eup ); + +} +#endif /* BSD < 199506 */ +#endif /* __FreeBSD__ */ diff --git a/sys/dev/hea/eni.h b/sys/dev/hea/eni.h new file mode 100644 index 0000000..ff4a81b --- /dev/null +++ b/sys/dev/hea/eni.h @@ -0,0 +1,499 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: eni.h,v 1.7 1998/06/29 19:45:14 jpt Exp $ + * + */ + +/* + * Efficient ENI Adapter Support + * + * Protocol and implementation definitions + * + */ + +#ifndef _ENI_ENI_H +#define _ENI_ENI_H + +#include <pci/pcireg.h> +#include <pci/pcivar.h> + +/* + * Physical device name - used to configure HARP devices + */ +#ifndef ENI_DEV_NAME +#define ENI_DEV_NAME "hea" /* HARP Efficient ATM */ +#endif + +#define ENI_MAX_UNITS 4 + +#define ENI_IFF_MTU 9188 +#define ENI_MAX_VCI 1023 /* 0 - 1023 */ +#define ENI_MAX_VPI 0 + +#define ENI_IFQ_MAXLEN 1000 /* rx/tx queue lengths */ + +#ifdef BSD +/* + * Size of small and large receive buffers + */ +#define ENI_SMALL_BSIZE 64 +#define ENI_LARGE_BSIZE MCLBYTES +#endif /* BSD */ + +/* + * ENI memory map offsets IN WORDS, not bytes + * + * The Efficient Adapter implements a 4 MB address space. The lower + * 2 MB are used by bootprom (E)EPROM and by chipset registers such + * as the MIDWAY and SUNI chips. The (upto) upper 2 MB is used for + * RAM. Of the RAM, the lower 28 KB is used for fixed tables - the + * VCI table, the RX and TX DMA queues, and the Service List queue. + * Memory above the 28 KB range is available for RX and TX buffers. + * + * NOTE: Access to anything other then the (E)EPROM MUST be as a 32 bit + * access. Also note that Efficient uses both byte addresses and word + * addresses when describing offsets. BE CAREFUL or you'll get confused! + */ +/* + * Size of memory space reserved for registers and expansion (e)eprom. + */ +#define ENI_REG_SIZE 0x200000 /* Two megabytes */ + +#define SUNI_OFFSET 0x008000 /* SUNI chip registers */ +#define MIDWAY_OFFSET 0x010000 /* MIDWAY chip registers */ +#define RAM_OFFSET 0x080000 /* Adapter RAM */ +#define VCITBL_OFFSET 0x080000 /* VCI Table offset */ +#define RXQUEUE_OFFSET 0x081000 /* RX DMA Queue offset */ +#define TXQUEUE_OFFSET 0x081400 /* TX DMA Queue offset */ +#define SVCLIST_OFFSET 0x081800 /* SVC List Queue offset */ + +#define SEGBUF_BASE 0x007000 /* Base from start of RAM */ + +#define DMA_LIST_SIZE 512 /* 1024 words / 2 words per entry */ +#define SVC_LIST_SIZE 1024 /* 1024 words / 1 word per entry */ + +/* + * Values for testing size of RAM on adapter + * + * Efficient has (at least) two different memory sizes available. One + * is a client card which has either 128 KB or 512 KB RAM, the other + * is a server card which has 2 MB RAM. The driver will size and test + * the memory to correctly determine what's available. + */ +#define MAX_ENI_MEM 0x200000 /* 2 MB - max. mem supported */ +#define TEST_STEP 0x000400 /* Look at 1 KB steps */ +#define TEST_PAT 0xA5A5A5A5 /* Test pattern */ + +/* + * Values for memory allocator + */ +#define ENI_BUF_PGSZ 1024 /* Allocation unit of buffers */ +#define ENI_BUF_NBIT 8 /* Number of bits to get from */ + /* min buffer (1KB) to max (128KB) */ + +/* + * Values for allocating TX buffers + */ +#define MAX_CLIENT_RAM 512 /* Most RAM a client card will have */ +#define TX_SMALL_BSIZE 32 /* Small buffer - 32KB */ +#define TX_LARGE_BSIZE 128 /* Large buffer - 128KB */ + +/* + * Values for allocating RX buffers + */ +#define RX_SIG_BSIZE 4 /* Signalling buffer - 4KB */ +#define RX_CLIENT_BSIZE 16 /* Client buffer - 16KB */ +#define RX_SERVER_BSIZE 32 /* Server buffer - 32KB */ + +/* + * Adapter bases all addresses off of some power from 1KB. Thus, it + * only needs to store the most sigificant bits and can drop the lower + * 10 bits. + */ +#define ENI_LOC_PREDIV 10 /* Bits location is shifted */ + /* Location is prescaled by 1KB */ + /* before use in various places */ + +#define MIDWAY_DELAY 10 /* Time to wait for Midway finish */ + +/* + * Define the MIDWAY register offsets and any interesting bits within + * the register + */ +#define MIDWAY_ID 0x00 /* ID/Reset register */ + #define MIDWAY_RESET 0 /* iWrite of any value */ + #define ID_SHIFT 27 /* Midway ID version */ + #define ID_MASK 0x1F /* ID mask */ + #define MID_SHIFT 7 /* Mother board ID */ + #define MID_MASK 0x7 /* MID mask */ + #define DID_SHIFT 0 /* Daughter board ID */ + #define DID_MASK 0x1F /* DID mask */ + /* + * Efficient defines the following IDs for their adapters: + * 0x420/0x620 - SONET MMF, client memory size + * 0x430/0x630 - SONET MMF, server memory size + * 0x424/0x624 - UTP-5, client memory size + * 0x434/0x634 - UTP-5, server memory size + */ + #define MEDIA_MASK 0x04 /* Mask off UTP-5/MMF media */ + +#define MIDWAY_ISA 0x01 /* Interrupt Status Ack. */ + /* Reading this register */ + /* also acknowledges the */ + /* posted interrupt(s) */ + +#define MIDWAY_IS 0x02 /* Interrupt Status */ + /* Reading this register */ + /* does NOT acknowledge the */ + /* posted interrupt(s) */ + /* Interrupt names */ + #define ENI_INT_STAT 0x00000001 + #define ENI_INT_SUNI 0x00000002 + #define ENI_INT_SERVICE 0x00000004 + #define ENI_INT_TX_DMA 0x00000008 + #define ENI_INT_RX_DMA 0x00000010 + #define ENI_INT_DMA_ERR 0x00000020 + #define ENI_INT_DMA_LERR 0x00000040 + #define ENI_INT_IDEN 0x00000080 + #define ENI_INT_DMA_OVFL 0x00000100 + #define ENI_INT_TX_MASK 0x0001FE00 + +#define MIDWAY_IE 0x03 /* Interrupt Enable register */ + /* Interrupt enable bits are the same as the Interrupt names */ + +#define MIDWAY_MASTER 0x04 /* Master Control */ + /* Master control bits */ + #define ENI_M_WAIT500 0x00000001 /* Disable interrupts .5 ms */ + #define ENI_M_WAIT1 0x00000002 /* Disable interrupts 1 ms */ + #define ENI_M_RXENABLE 0x00000004 /* Enable RX engine */ + #define ENI_M_TXENABLE 0x00000008 /* Enable TX engine */ + #define ENI_M_DMAENABLE 0x00000010 /* Enable DMA */ + #define ENI_M_TXLOCK 0x00000020 /* 0: Streaming, 1: Lock */ + #define ENI_M_INTSEL 0x000001C0 /* Int Select mask */ + #define ENI_ISEL_SHIFT 6 /* Bits to shift ISEL value */ + +#define MIDWAY_STAT 0x05 /* Statistics register */ + +#define MIDWAY_SVCWR 0x06 /* Svc List write pointer */ + #define SVC_SIZE_MASK 0x3FF /* Valid bits in svc pointer */ + +#define MIDWAY_DMAADDR 0x07 /* Current virtual DMA addr */ + +#define MIDWAY_RX_WR 0x08 /* Write ptr to RX DMA queue */ + +#define MIDWAY_RX_RD 0x09 /* Read ptr to RX DMA queue */ + +#define MIDWAY_TX_WR 0x0A /* Write ptr to TX DMA queue */ + +#define MIDWAY_TX_RD 0x0B /* Read ptr to TX DMA queue */ + +/* + * Registers 0x0C - 0x0F are unused + */ + +/* + * MIDWAY supports 8 transmit channels. Each channel has 3 registers + * to control operation. Each new channel starts on N * 4 set. Thus, + * channel 0 uses register 0x10 - 0x13, channel 1 uses 0x14 - 0x17, etc. + * Register 0x13 + N * 4 is unused. + */ + +#define MIDWAY_TXPLACE 0x10 /* Channel N TX location */ + #define TXSIZE_SHIFT 11 /* Bits to shift size by */ + #define TX_PLACE_MASK 0x7FF /* Valid bits in TXPLACE */ + +#define MIDWAY_RDPTR 0x11 /* Channel N Read ptr */ + +#define MIDWAY_DESCR 0x12 /* Channel N Descr ptr */ + +/* + * Register 0x30 on up are unused + */ + +/* + * Part of PCI configuration registers but not defined in <pci/pcireg.h> + */ +#define PCI_CONTROL_REG 0x60 +#define ENDIAN_SWAP_DMA 0x80 /* Enable endian swaps on DMA */ + +/* + * The Efficient adapter references adapter RAM through the use of + * location and size values. Eight sizes are defined. When allocating + * buffers, there size must be rounded up to the next size which will + * hold the requested size. Buffers are allocated on 'SIZE' boundaries. + * See eni_buffer.c for more info. + */ + +/* + * Buffer SIZE definitions - in words, so from 1 KB to 128 KB + */ +#define SIZE_256 0x00 +#define SIZE_512 0x01 +#define SIZE_1K 0x02 +#define SIZE_2K 0x03 +#define SIZE_4K 0x04 +#define SIZE_8K 0x05 +#define SIZE_16K 0x06 +#define SIZE_32K 0x07 + +/* + * Define values for DMA type - DMA descriptors include a type field and a + * count field except in the special case of JK (just-kidding). With type JK, + * the count field should be set to the address which will be loaded + * into the pointer, ie. where the pointer should next point to, since + * JK doesn't have a "size" associated with it. JK DMA is used to skip + * over descriptor words, and to strip off padding of AAL5 PDUs. The + * DMA_nWORDM types will do a n word DMA burst, but the count field + * does not have to equal n. Any difference results in garbage filling + * the remaining words of the DMA. These types could be used where a + * particular burst size yields better DMA performance. + */ +#define DMA_WORD 0x00 +#define DMA_BYTE 0x01 +#define DMA_HWORD 0x02 +#define DMA_JK 0x03 +#define DMA_4WORD 0x04 +#define DMA_8WORD 0x05 +#define DMA_16WORD 0x06 +#define DMA_2WORD 0x07 +#define DMA_4WORDM 0x0C +#define DMA_8WORDM 0x0D +#define DMA_16WORDM 0x0E +#define DMA_2WORDM 0x0F + +/* + * Define the size of the local DMA list we'll build before + * giving up on the PDU. + */ +#define TEMP_DMA_SIZE 120 /* Enough for 58/59 buffers */ + +#define DMA_COUNT_SHIFT 16 /* Number of bits to shift count */ + /* in DMA descriptor word */ +#define DMA_VCC_SHIFT 6 /* Number of bits to shift RX VCC or */ + /* TX channel in DMA descriptor word */ +#define DMA_END_BIT 0x20 /* Signal end of DMA list */ + +/* + * Defines for VCI table + * + * The VCI table is a 1K by 4 word table allowing up to 1024 (0-1023) + * VCIs. Entries into the table use the VCI number as the index. + */ +struct vci_table { + u_long vci_control; /* Control word */ + u_long vci_descr; /* Descr/ReadPtr */ + u_long vci_write; /* WritePtr/State/Cell count */ + u_long vci_crc; /* ongoing CRC calculation */ +}; +typedef volatile struct vci_table VCI_Table; + +#define VCI_MODE_SHIFT 30 /* Shift to get MODE field */ +#define VCI_MODE_MASK 0x3FFFFFFF /* Bits to strip MODE off */ +#define VCI_PTI_SHIFT 29 /* Shift to get PTI mode field */ +#define VCI_LOC_SHIFT 18 /* Shift to get location field */ +#define VCI_LOC_MASK 0x7FF /* Valid bits in location field */ +#define VCI_SIZE_SHIFT 15 /* Shift to get size field */ +#define VCI_SIZE_MASK 7 /* Valid bits in size field */ +#define VCI_IN_SERVICE 1 /* Mask for IN_SERVICE field */ + +/* + * Defines for VC mode + */ +#define VCI_MODE_TRASH 0x00 /* Trash all cells for this VC */ +#define VCI_MODE_AAL0 0x01 /* Reassemble as AAL_0 PDU */ +#define VCI_MODE_AAL5 0x02 /* Reassemble as AAL_5 PDU */ +/* + * Defines for handling cells with PTI(2) set to 1. + */ +#define PTI_MODE_TRASH 0x00 /* Trash cell */ +#define PTI_MODE_PRESV 0x01 /* Send cell to OAM channel */ +/* + * Current state of VC + */ +#define VCI_STATE_IDLE 0x00 /* VC is idle */ +#define VCI_STATE_REASM 0x01 /* VC is reassembling PDU */ +#define VCI_STATE_TRASH 0x03 /* VC is trashing cells */ + +/* + * RX Descriptor word values + */ +#define DESCR_TRASH_BIT 0x1000 /* VCI was trashing cells */ +#define DESCR_CRC_ERR 0x0800 /* PDU has CRC error */ +#define DESCR_CELL_COUNT 0x07FF /* Mask to get cell count */ +/* + * TX Descriptor word values + */ +#define TX_IDEN_SHIFT 28 /* Unique identifier location */ +#define TX_MODE_SHIFT 27 /* AAL5 or AAL0 */ +#define TX_VCI_SHIFT 4 /* Bits to shift VCI value */ + +/* + * When setting up descriptor words (at head of segmentation queues), there + * is a unique identifier used to help detect sync problems. + */ +#define MIDWAY_UNQ_ID 0x0B + +/* + * Defines for cell sizes + */ +#define BYTES_PER_CELL 48 /* Number of data bytes per cell */ +#define WORDS_PER_CELL 12 /* Number of data words per cell */ + +/* + * Access to Serial EEPROM [as opposed to expansion (E)PROM]. + * + * This is a ATMEL AT24C01 serial EEPROM part. + * See http://www.atmel.com/atmel/products/prod162.htm for timimg diagrams + * for START/STOP/ACK/READ cycles. + */ +#define SEEPROM PCI_CONTROL_REG /* Serial EEPROM is accessed thru */ + /* PCI control register */ +#define SEPROM_DATA 0x02 /* SEEPROM DATA line */ +#define SEPROM_CLK 0x01 /* SEEPROM CLK line */ +#define SEPROM_SIZE 128 /* Size of Serial EEPROM */ +#define SEPROM_MAC_OFF 64 /* Offset to MAC address */ +#define SEPROM_SN_OFF 112 /* Offset to serial number */ +#define SEPROM_DELAY 10 /* Delay when strobing CLK/DATA lines */ + +/* + * Host protocol control blocks + * + */ + +/* + * Device VCC Entry + * + * Contains the common and ENI-specific information for each VCC + * which is opened through a ENI device. + */ +struct eni_vcc { + struct cmn_vcc ev_cmn; /* Common VCC stuff */ + caddr_t ev_rxbuf; /* Receive buffer */ + u_long ev_rxpos; /* Adapter buffer read pointer */ +}; +typedef struct eni_vcc Eni_vcc; + +#define ev_next ev_cmn.cv_next +#define ev_toku ev_cmn.cv_toku +#define ev_upper ev_cmn.cv_upper +#define ev_connvc ev_cmn.cv_connvc +#define ev_state ev_cmn.cv_state + +typedef volatile unsigned long * Eni_mem; + +/* + * Define the ID's we'll look for in the PCI config + * register when deciding if we'll support this device. + * The DEV_ID will need to be turned into an array of + * ID's in order to support multiple adapters with + * the same driver. + */ +#define EFF_VENDOR_ID 0x111A +#define EFF_DEV_ID 0x0002 + +/* + * Memory allocator defines and buffer descriptors + */ +#define MEM_FREE 0 +#define MEM_INUSE 1 + +typedef struct mbd Mbd; +struct mbd { + Mbd *prev; + Mbd *next; + caddr_t base; /* Adapter base address */ + int size; /* Size of buffer */ + int state; /* INUSE or FREE */ +}; + +/* + * We use a hack to allocate a smaller RX buffer for signalling + * channels as they tend to have small MTU lengths. + */ +#define UNI_SIG_VCI 5 + +/* + * Device Unit Structure + * + * Contains all the information for a single device (adapter). + */ +struct eni_unit { + Cmn_unit eu_cmn; /* Common unit stuff */ + pcici_t eu_pcitag; /* PCI tag */ + Eni_mem eu_base; /* Adapter memory base */ + Eni_mem eu_ram; /* Adapter RAM */ + u_long eu_ramsize; + + Eni_mem eu_suni; /* SUNI registers */ + + Eni_mem eu_midway; /* MIDWAY registers */ + + VCI_Table *eu_vcitbl; /* VCI Table */ + Eni_mem eu_rxdma; /* Receive DMA queue */ + Eni_mem eu_txdma; /* Transmit DMA queue */ + Eni_mem eu_svclist; /* Service list */ + u_long eu_servread; /* Read pointer into Service list */ + + caddr_t eu_txbuf; /* One large TX buff for everything */ + u_long eu_txsize; /* Size of TX buffer */ + u_long eu_txpos; /* Current word being stored in RAM */ + u_long eu_txfirst; /* First word of unack'ed data */ + + u_long eu_trash; + u_long eu_ovfl; + + struct ifqueue eu_txqueue; + u_long eu_txdmawr; + struct ifqueue eu_rxqueue; + u_long eu_rxdmawr; /* DMA list write pointer */ + + u_char eu_seeprom[SEPROM_SIZE]; /* Serial EEPROM contents */ + u_int eu_sevar; /* Unique (per unit) seeprom var. */ + + Mbd *eu_memmap; /* Adapter RAM memory allocator map */ + int eu_memclicks[ENI_BUF_NBIT];/* Count of INUSE buffers */ + + Eni_stats eu_stats; /* Statistics */ + +}; +typedef struct eni_unit Eni_unit; + +#define eu_pif eu_cmn.cu_pif +#define eu_unit eu_cmn.cu_unit +#define eu_flags eu_cmn.cu_flags +#define eu_mtu eu_cmn.cu_mtu +#define eu_open_vcc eu_cmn.cu_open_vcc +#define eu_vcc eu_cmn.cu_vcc +#define eu_vcc_pool eu_cmn.cu_vcc_pool +#define eu_nif_pool eu_cmn.cu_nif_pool +#define eu_ioctl eu_cmn.cu_ioctl +#define eu_instvcc eu_cmn.cu_instvcc +#define eu_openvcc eu_cmn.cu_openvcc +#define eu_closevcc eu_cmn.cu_closevcc +#define eu_output eu_cmn.cu_output +#define eu_config eu_cmn.cu_config + +#endif /* _ENI_ENI_H */ diff --git a/sys/dev/hea/eni_buffer.c b/sys/dev/hea/eni_buffer.c new file mode 100644 index 0000000..35d1b13 --- /dev/null +++ b/sys/dev/hea/eni_buffer.c @@ -0,0 +1,465 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: eni_buffer.c,v 1.8 1998/08/26 23:28:53 mks Exp $ + * + */ + +/* + * Efficient ENI Adapter Support + * ----------------------------- + * + * Handle adapter memory buffers for ENI adapters + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: eni_buffer.c,v 1.8 1998/08/26 23:28:53 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <dev/hea/eni_stats.h> +#include <dev/hea/eni.h> +#include <dev/hea/eni_var.h> + +static int eni_test_memory __P((Eni_unit *)); + +/* + * The host is going to manage (that is, allocate and free) buffers + * in the adapters RAM space. We are going to implement this as a + * linked list describing FREE and INUSE memory segments. Initially, + * the list contains one element with all memory marked free. As requests + * are made, we search the list until we find the first free element + * which can satisfy the request. If necessary, we will break the free + * element into an INUSE element, and a new FREE element. When freeing + * memory, we look at adjacent elements and if one or more are free, + * we will combine into a single larger FREE element. + */ + +/* + * This is for testing purposes. Since there are two versions of + * the Efficient adapter with different memory sizes, this allows + * us to fool an adapter with more memory into thinking it has less. + */ +int eni_mem_max = MAX_ENI_MEM; /* Default to all available memory */ + +/* + * Size and test adapter RAM + * + * Walk through adapter RAM writing known patterns and reading back + * for comparison. We write more than one pattern on the off chance + * that we "get lucky" and read what we expected. + * + * Arguments: + * eup pointer to device unit structure + * + * Returns + * size memory size in bytes + */ +static int +eni_test_memory ( eup ) + Eni_unit *eup; +{ + int ram_size = 0; + int i; + Eni_mem mp; + + /* + * Walk through to maximum looking for RAM + */ + for ( i = 0; i < MAX_ENI_MEM; i += TEST_STEP ) { + mp = (Eni_mem)((int)eup->eu_ram + i); + /* write pattern */ + *mp = (u_long)TEST_PAT; + /* read pattern, match? */ + if ( *mp == (u_long)TEST_PAT ) { + /* yes - write inverse pattern */ + *mp = (u_long)~TEST_PAT; + /* read pattern, match? */ + if ( *mp == (u_long)~TEST_PAT ) { + /* yes - assume another 1K available */ + ram_size = i + TEST_STEP; + } else + break; + } else + break; + } + /* + * Clear all RAM to initial value of zero. + * This makes sure we don't leave anything funny in the + * queues. + */ + KM_ZERO ( eup->eu_ram, ram_size ); + + /* + * If we'd like to claim to have less memory, here's where + * we do so. We take the minimum of what we'd like and what + * we really found on the adapter. + */ + ram_size = MIN ( ram_size, eni_mem_max ); + + return ( ram_size ); + +} + +/* + * Initialize our memory allocator. + * + * Arguments: + * eup Pointer to per unit structure + * + * Returns: + * size Physical RAM size + * -1 failed to initialize memory + * + */ +int +eni_init_memory ( eup ) + Eni_unit *eup; +{ + + /* + * Have we (somehow) been called before? + */ + if ( eup->eu_memmap != NULL ) + { + /* Oops - it's already been initialized */ + return -1; + } + + /* + * Allocate initial element which will hold all of memory + */ + if ( ( eup->eu_memmap = (Mbd *)KM_ALLOC(sizeof(Mbd), M_DEVBUF, + M_NOWAIT ) ) == NULL ) + { + /* Memory allocation error */ + return -1; + } + + /* + * Test and size memory + */ + eup->eu_ramsize = eni_test_memory ( eup ); + + /* + * Initialize a one element list which contains + * all buffer memory + */ + eup->eu_memmap->prev = eup->eu_memmap->next = NULL; + eup->eu_memmap->base = (caddr_t)SEGBUF_BASE; + eup->eu_memmap->size = eup->eu_ramsize - SEGBUF_BASE; + eup->eu_memmap->state = MEM_FREE; + + return ( eup->eu_ramsize ); +} + +/* + * Allocate a buffer from adapter RAM. Due to constraints on the card, + * we may roundup the size request to the next largest chunksize. Note + * also that we must pay attention to address alignment within adapter + * memory as well. + * + * Arguments: + * eup pointer to per unit structure + * size pointer to requested size - in bytes + * + * Returns: + * addr address relative to adapter of allocated memory + * size modified to reflect actual size of buffer + * + */ +caddr_t +eni_allocate_buffer ( eup, size ) + Eni_unit *eup; + u_long *size; +{ + int nsize; + int nclicks; + Mbd *eptr = eup->eu_memmap; + + /* + * Initial size requested + */ + nsize = *size; + + /* + * Find the buffer size which will hold this request. There + * are 8 possible sizes, each a power of two up, starting at + * 256 words or 1024 bytes. + */ + for ( nclicks = 0; nclicks < ENI_BUF_NBIT; nclicks++ ) + if ( ( 1 << nclicks ) * ENI_BUF_PGSZ >= nsize ) + break; + + /* + * Request was for larger then the card supports + */ + if ( nclicks >= ENI_BUF_NBIT ) { + eup->eu_stats.eni_st_drv.drv_mm_toobig++; + /* Indicate 0 bytes allocated */ + *size = 0; + /* Return NULL buffer */ + return ( (caddr_t)NULL ); + } + + /* + * New size will be buffer size + */ + nsize = ( 1 << nclicks ) * ENI_BUF_PGSZ; + + /* + * Look through memory for a segment large enough to + * hold request + */ + while ( eptr ) { + /* + * State must be FREE and size must hold request + */ + if ( eptr->state == MEM_FREE && eptr->size >= nsize ) + { + /* + * Request will fit - now check if the + * alignment needs fixing + */ + if ( ((u_int)eptr->base & (nsize-1)) != 0 ) + { + caddr_t nbase; + + /* + * Calculate where the buffer would have to + * fall to be aligned. + */ + nbase = (caddr_t)((u_int)( eptr->base + nsize ) & + ~(nsize-1)); + /* + * If we use this alignment, will it still fit? + */ + if ( (eptr->size - (nbase - eptr->base)) >= 0 ) + { + Mbd *etmp; + + /* Yep - create a new segment */ + etmp = (Mbd *)KM_ALLOC(sizeof(Mbd), M_DEVBUF, + M_NOWAIT ); + if ( etmp == (Mbd *)NULL ) { + /* + * Couldn't allocate a new descriptor. Indicate + * failure and exit now or we'll start losing + * memory. + */ + eup->eu_stats.eni_st_drv.drv_mm_nodesc++; + *size = 0; + return ( (caddr_t)NULL ); + } + /* Place it in the list */ + etmp->next = eptr->next; + if ( etmp->next ) + etmp->next->prev = etmp; + etmp->prev = eptr; + eptr->next = etmp; + /* Fill in new base and size */ + etmp->base = nbase; + etmp->size = eptr->size - ( nbase - eptr->base ); + /* Adjust old size */ + eptr->size -= etmp->size; + /* Mark its state */ + etmp->state = MEM_FREE; + eptr = etmp; + /* Done - outa here */ + break; + } + } else + break; /* Alignment is okay - we're done */ + } + /* Haven't found anything yet - keep looking */ + eptr = eptr->next; + } + + if ( eptr != NULL ) + { + /* Found a usable segment - grab what we need */ + /* Exact fit? */ + if ( eptr->size == nsize ) + /* Mark it as INUSE */ + eptr->state = MEM_INUSE; + else + { + Mbd *etmp; + /* larger then we need - split it */ + + etmp = (Mbd *)KM_ALLOC(sizeof(Mbd), M_DEVBUF, M_NOWAIT ); + if ( etmp == (Mbd *)NULL ) { + /* + * Couldn't allocate new descriptor. Indicate + * failure and exit now or we'll start losing + * memory. + */ + eup->eu_stats.eni_st_drv.drv_mm_nodesc++; + *size = 0; + return ( (caddr_t)NULL ); + } + /* Place new element in list */ + etmp->next = eptr->next; + if ( etmp->next ) + etmp->next->prev = etmp; + etmp->prev = eptr; + eptr->next = etmp; + /* Set new base, size and state */ + etmp->base = eptr->base + nsize; + etmp->size = eptr->size - nsize; + etmp->state = MEM_FREE; + /* Adjust size and state of element we intend to use */ + eptr->size = nsize; + eptr->state = MEM_INUSE; + } + } + + /* After all that, did we find a usable buffer? */ + if ( eptr ) + { + /* Record another inuse buffer of this size */ + if ( eptr->base ) + eup->eu_memclicks[nclicks]++; + + /* + * Return true size of allocated buffer + */ + *size = eptr->size; + /* + * Make address relative to start of RAM since + * its (the address) for use by the adapter, not + * the host. + */ + return ((caddr_t)eptr->base); + } else { + eup->eu_stats.eni_st_drv.drv_mm_nobuf++; + /* No buffer to return - indicate zero length */ + *size = 0; + /* Return NULL buffer */ + return ( (caddr_t)NULL ); + } +} + +/* + * Procedure to release a buffer previously allocated from adapter + * RAM. When possible, we'll compact memory. + * + * Arguments: + * eup pointer to per unit structure + * base base adapter address of buffer to be freed + * + * Returns: + * none + * + */ +void +eni_free_buffer ( eup, base ) + Eni_unit *eup; + caddr_t base; +{ + Mbd *eptr = eup->eu_memmap; + int nclicks; + + /* Look through entire list */ + while ( eptr ) + { + /* Is this the buffer to be freed? */ + if ( eptr->base == base ) + { + /* + * We're probably asking for trouble but, + * assume this is it. + */ + if ( eptr->state != MEM_INUSE ) + { + eup->eu_stats.eni_st_drv.drv_mm_notuse++; + /* Huh? Something's wrong */ + return; + } + /* Reset state to FREE */ + eptr->state = MEM_FREE; + + /* Determine size for stats info */ + for ( nclicks = 0; nclicks < ENI_BUF_NBIT; nclicks++ ) + if ( ( 1 << nclicks ) * ENI_BUF_PGSZ == eptr->size ) + break; + + /* Valid size? Yes - decrement inuse count */ + if ( nclicks < ENI_BUF_NBIT ) + eup->eu_memclicks[nclicks]--; + + /* Try to compact neighbors */ + /* with previous */ + if ( eptr->prev ) + if ( eptr->prev->state == MEM_FREE ) + { + Mbd *etmp = eptr; + /* Add to previous block */ + eptr->prev->size += eptr->size; + /* Set prev block to skip this one */ + eptr->prev->next = eptr->next; + /* Set next block to skip this one */ + if ( eptr->next ) + eptr->next->prev = eptr->prev; + /* Reset to where we want to be */ + eptr = eptr->prev; + /* and free this element */ + (void)KM_FREE(etmp, etmp->size, M_DEVBUF); + } + /* with next */ + if ( eptr->next ) + if ( eptr->next->state == MEM_FREE ) + { + Mbd *etmp = eptr->next; + + /* add following block in */ + eptr->size += etmp->size; + /* set next next block to skip next block */ + if ( etmp->next ) + etmp->next->prev = eptr; + /* skip next block */ + eptr->next = etmp->next; + /* and free next element */ + (void)KM_FREE(etmp, etmp->size, M_DEVBUF); + } + /* + * We've freed the buffer and done any compaction, + * we needn't look any further... + */ + return; + } + eptr = eptr->next; + } + + if ( eptr == NULL ) + { + /* Oops - failed to find the buffer. This is BAD */ + eup->eu_stats.eni_st_drv.drv_mm_notfnd++; + } + +} + diff --git a/sys/dev/hea/eni_globals.c b/sys/dev/hea/eni_globals.c new file mode 100644 index 0000000..a2a51fa --- /dev/null +++ b/sys/dev/hea/eni_globals.c @@ -0,0 +1,102 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: eni_globals.c,v 1.2 1997/05/06 22:07:52 mks Exp $ + * + */ + +/* + * Efficient ENI Adapter Support + * ----------------------------- + * + * Global variable definitions + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: eni_globals.c,v 1.2 1997/05/06 22:07:52 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <dev/hea/eni_stats.h> +#include <dev/hea/eni.h> +#include <dev/hea/eni_var.h> + +/* + * Device unit table + */ +Eni_unit *eni_units[ENI_MAX_UNITS] = {NULL}; + +/* + * ATM Interface services + */ +/* + * AAL5 service stack + */ +static struct stack_defn eni_svaal5 = { + NULL, + SAP_CPCS_AAL5, + SDF_TERM, + atm_dev_inst, + atm_dev_lower, + NULL, + 0, +}; +/* + * Efficient hardware doesn't support AAL3/4. Don't define + * an AAL3/4 stack. + */ +/* + * AAL0 service stack + */ +static struct stack_defn eni_svaal0 = { + &eni_svaal5, + SAP_ATM, + SDF_TERM, + atm_dev_inst, + atm_dev_lower, + NULL, + 0, +}; +struct stack_defn *eni_services = &eni_svaal0; + +/* + * Storage pools + */ +struct sp_info eni_nif_pool = { + "eni nif pool", /* si_name */ + sizeof(struct atm_nif), /* si_blksiz */ + 5, /* si_blkcnt */ + 20 /* si_maxallow */ +}; + +struct sp_info eni_vcc_pool = { + "eni vcc pool", /* si_name */ + sizeof(Eni_vcc), /* si_blksiz */ + 10, /* si_blkcnt */ + 100 /* si_maxallow */ +}; + diff --git a/sys/dev/hea/eni_if.c b/sys/dev/hea/eni_if.c new file mode 100644 index 0000000..41ffd48 --- /dev/null +++ b/sys/dev/hea/eni_if.c @@ -0,0 +1,270 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: eni_if.c,v 1.6 1998/08/26 23:28:53 mks Exp $ + * + */ + +/* + * Efficient ENI Adapter Support + * ----------------------------- + * + * Network interface layer support + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: eni_if.c,v 1.6 1998/08/26 23:28:53 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <dev/hea/eni_stats.h> +#include <dev/hea/eni.h> +#include <dev/hea/eni_suni.h> +#include <dev/hea/eni_var.h> + +static void eni_get_stats __P((Eni_unit *)); + +/* + * SUNI statistics counters take one of three forms: + * single byte value (0x0 - 0xff) + * two byte value (0x0 - 0xffff) + * two + 1/2 (three) byte value + * (0x0 - 0x0fffff) + */ +#define READ_ONE(x) ( (eup->eu_suni[(x)] & 0xff) ) + +#define READ_TWO(x) ( (eup->eu_suni[(x)+1] & 0xff) << 8 | \ + (eup->eu_suni[(x)] & 0xff) ) + +#define READ_THREE(x) ( (eup->eu_suni[(x)+2] & 0xf) << 16 | \ + (eup->eu_suni[(x)+1] & 0xff) << 8 | \ + (eup->eu_suni[(x)] & 0xff) ) + +/* + * Do an initial read of the error counters without saving them. + * In effect, this will "zero" our idea of the number of errors + * which have occurred since the driver was loaded. + * + * Arguments: + * eup pointer to per unit structure + * + * Returns: + * none + * + */ +void +eni_zero_stats ( eup ) + Eni_unit *eup; +{ + int val; + + /* + * Write the SUNI master control register which + * will cause all the statistics counters to be + * loaded. + */ + eup->eu_suni[SUNI_MASTER_REG] = eup->eu_suni[SUNI_MASTER_REG]; + + /* + * Delay to allow for counter load time... + */ + DELAY ( SUNI_DELAY ); + + /* + * Statistics counters contain the number of events + * since the last time the counter was read. + */ + val = READ_TWO ( SUNI_SECT_BIP_REG ); /* oc3_sect_bip8 */ + val = READ_TWO ( SUNI_PATH_BIP_REG ); /* oc3_path_bip8 */ + val = READ_THREE ( SUNI_LINE_BIP_REG ); /* oc3_line_bip24 */ + val = READ_THREE ( SUNI_LINE_FEBE_REG ); /* oc3_line_febe */ + val = READ_TWO ( SUNI_PATH_FEBE_REG ); /* oc3_path_febe */ + val = READ_ONE ( SUNI_HECS_REG ); /* oc3_hec_corr */ + val = READ_ONE ( SUNI_UHECS_REG ); /* oc3_hec_uncorr */ +} + +/* + * Retrieve SUNI stats + * + * Arguments: + * eup pointer to per unit structure + * + * Returns: + * none + * + */ +static void +eni_get_stats ( eup ) + Eni_unit *eup; +{ + /* + * Write the SUNI master control register which + * will cause all the statistics counters to be + * loaded. + */ + eup->eu_suni[SUNI_MASTER_REG] = eup->eu_suni[SUNI_MASTER_REG]; + + /* + * Delay to allow for counter load time... + */ + DELAY ( 10 ); + + /* + * Statistics counters contain the number of events + * since the last time the counter was read. + */ + eup->eu_stats.eni_st_oc3.oc3_sect_bip8 += + READ_TWO ( SUNI_SECT_BIP_REG ); + eup->eu_stats.eni_st_oc3.oc3_path_bip8 += + READ_TWO ( SUNI_PATH_BIP_REG ); + eup->eu_stats.eni_st_oc3.oc3_line_bip24 += + READ_THREE ( SUNI_LINE_BIP_REG ); + eup->eu_stats.eni_st_oc3.oc3_line_febe += + READ_THREE ( SUNI_LINE_FEBE_REG ); + eup->eu_stats.eni_st_oc3.oc3_path_febe += + READ_TWO ( SUNI_PATH_FEBE_REG ); + eup->eu_stats.eni_st_oc3.oc3_hec_corr += + READ_ONE ( SUNI_HECS_REG ); + eup->eu_stats.eni_st_oc3.oc3_hec_uncorr += + READ_ONE ( SUNI_UHECS_REG ); +} + +/* + * Handle netatm core service interface ioctl requests + * + * Called at splnet. + * + * Arguments: + * code ioctl function (sub)code + * data data to/from ioctl + * arg optional code-specific argument + * + * Returns: + * 0 request processed successfully + * error request failed - reason code + * + */ +int +eni_atm_ioctl ( code, data, arg ) + int code; + caddr_t data; + caddr_t arg; +{ + struct atminfreq *aip = (struct atminfreq *)data; + struct atm_pif *pip = (struct atm_pif *)arg; + Eni_unit *eup = (Eni_unit *)pip; + caddr_t buf = aip->air_buf_addr; + struct air_vinfo_rsp *avr; + int count, len, buf_len = aip->air_buf_len; + int err = 0; + char ifname[2*IFNAMSIZ]; + + ATM_DEBUG2("eni_atm_ioctl: code=%d, opcode=%d\n", + code, aip->air_opcode ); + + switch ( aip->air_opcode ) { + + case AIOCS_INF_VST: + /* + * Get vendor statistics + */ + if ( eup == NULL ) + return ( ENXIO ); + sprintf ( ifname, "%s%d", pip->pif_name, pip->pif_unit ); + + /* + * Cast response structure onto user's buffer + */ + avr = (struct air_vinfo_rsp *)buf; + + /* + * How large is the response structure + */ + len = sizeof(struct air_vinfo_rsp); + + /* + * Sanity check - enough room for response structure? + */ + if ( buf_len < len ) + return ( ENOSPC ); + + /* + * Copy interface name into response structure + */ + if ( err = copyout ( ifname, avr->avsp_intf, IFNAMSIZ ) ) + break; + + /* + * Advance the buffer address and decrement the size + */ + buf += len; + buf_len -= len; + + /* + * Get the vendor stats (SUNI) from the hardware + */ + eni_get_stats ( eup ); + /* + * Stick as much of it as we have room for + * into the response + */ + count = MIN ( sizeof(Eni_stats), buf_len ); + + /* + * Copy stats into user's buffer. Return value is + * amount of data copied. + */ + if ( err = copyout ((void *)&eup->eu_stats, buf, + count)) + break; + buf += count; + buf_len -= count; + if ( count < sizeof(Eni_stats) ) + err = ENOSPC; + + /* + * Record amount we're returning as vendor info... + */ + if (err = copyout(&count, &avr->avsp_len, sizeof(int))) + break; + + /* + * Update the reply pointers and length + */ + aip->air_buf_addr = buf; + aip->air_buf_len = buf_len; + break; + + default: + err = ENOSYS; /* Operation not supported */ + break; + } + + return ( err ); + +} + diff --git a/sys/dev/hea/eni_init.c b/sys/dev/hea/eni_init.c new file mode 100644 index 0000000..d8106ab --- /dev/null +++ b/sys/dev/hea/eni_init.c @@ -0,0 +1,142 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: eni_init.c,v 1.6 1998/08/26 23:28:53 mks Exp $ + * + */ + +/* + * Efficient ENI Adapter Support + * ----------------------------- + * + * Driver initialization support + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: eni_init.c,v 1.6 1998/08/26 23:28:53 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <dev/hea/eni_stats.h> +#include <dev/hea/eni.h> +#include <dev/hea/eni_var.h> + +/* + * Initialize adapter for PDU processing + * + * Enable interrupts, set master control, initialize TX buffer, + * set initial pointers, etc. + * + * Arguments: + * eup pointer to device unit structure + * + * Returns: + * 0 successful + * error error condition + */ +int +eni_init ( eup ) + Eni_unit *eup; +{ + u_long words, order; + + /* + * Allocate one large TX buffer. Currently we use only one + * channel with full cell rate which all VCs will use. + * This will (probably) have to change (alot) when we + * implement QoS. + */ + /* + * Server cards, which have more then 512KB of RAM, will + * allocate a 128KB TX buffer, while client cards, with + * 512KB or less will allocate a 32KB TX buffer. + */ + words = ( eup->eu_ramsize > MAX_CLIENT_RAM * ENI_BUF_PGSZ ? + TX_LARGE_BSIZE : TX_SMALL_BSIZE ) * ENI_BUF_PGSZ; + if ( ( eup->eu_txbuf = eni_allocate_buffer ( eup, &words ) ) == + (caddr_t)NULL ) { + return ENOMEM; + } + eup->eu_txsize = words >> 2; /* Bytes to words */ + words >>= ENI_LOC_PREDIV; /* Predivide by 256 words */ + for ( order = -1; words; order++ ) + words >>= 1; + eup->eu_midway[MIDWAY_TXPLACE] = + (order << TXSIZE_SHIFT) | ((int)eup->eu_txbuf >> ENI_LOC_PREDIV); + eup->eu_txpos = eup->eu_midway[MIDWAY_DESCR] & 0x7FFF; + /* + * Set first word of unack'ed data to start + */ + eup->eu_txfirst = eup->eu_txpos; + + /* + * Set initial values of local DMA pointer used to prevent wraps + */ + eup->eu_txdmawr = 0; + eup->eu_rxdmawr = 0; + + /* + * Initialize queue's for receive/transmit pdus + */ + eup->eu_txqueue.ifq_maxlen = ENI_IFQ_MAXLEN; + eup->eu_rxqueue.ifq_maxlen = ENI_IFQ_MAXLEN; + + /* + * Acknowledge any interrupts + */ + (void) eup->eu_midway[MIDWAY_ISA]; + + /* + * "Zero" Sonet error counters + */ + eni_zero_stats ( eup ); + + /* + * Set master control register + * + * IntSel1 | LOCK_MODE | DMA_ENABLE | TX_ENABLE | RX_ENABLE + * + */ + eup->eu_midway[MIDWAY_MASTER] = 1 << ENI_ISEL_SHIFT | + ENI_M_DMAENABLE | ENI_M_TXENABLE | ENI_M_RXENABLE; + + /* + * Enable interrupts + */ + eup->eu_midway[MIDWAY_IE] = ENI_INT_SERVICE | ENI_INT_RX_DMA | + ENI_INT_TX_DMA | ENI_INT_DMA_ERR | ENI_INT_DMA_LERR | + ENI_INT_IDEN | ENI_INT_DMA_OVFL; + + /* + * Last thing to do is to indicate that we've finished initializing + * this unit. + */ + eup->eu_flags |= CUF_INITED; + + return 0; +} + diff --git a/sys/dev/hea/eni_intr.c b/sys/dev/hea/eni_intr.c new file mode 100644 index 0000000..e0a5642 --- /dev/null +++ b/sys/dev/hea/eni_intr.c @@ -0,0 +1,230 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: eni_intr.c,v 1.4 1998/08/26 23:28:54 mks Exp $ + * + */ + +/* + * Efficient ENI Adapter Support + * ----------------------------- + * + * Interrupt processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: eni_intr.c,v 1.4 1998/08/26 23:28:54 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <dev/hea/eni_stats.h> +#include <dev/hea/eni.h> +#include <dev/hea/eni_suni.h> +#include <dev/hea/eni_var.h> + +static void eni_suni_intr __P((Eni_unit *)); + +/* + * SUNI Interrupt processing + * + * Currently, we don't do anything more then clear the interrupt + * for the SUNI chip. + * + * Arguments: + * eup pointer to device unit structure + * + * Returns: + * none + * + */ +static void +eni_suni_intr ( eup ) + Eni_unit *eup; +{ + int SuniInt; + int val; + + SuniInt = eup->eu_suni[SUNI_IS_REG]; + + /* RSOPI */ + if ( SuniInt & SUNI_RSOPI ) + val = eup->eu_suni[SUNI_RSOP_REG]; + + /* RLOPI */ + if ( SuniInt & SUNI_RLOPI ) + val = eup->eu_suni[SUNI_RLOP_REG]; + + /* RPOPI */ + if ( SuniInt & SUNI_RPOPI ) + val = eup->eu_suni[SUNI_RPOP_IS_REG]; + + /* RACPI */ + if ( SuniInt & SUNI_RACPI ) + val = eup->eu_suni[SUNI_RACP_REG]; + + /* TACPI */ + if ( SuniInt & SUNI_TACPI ) + val = eup->eu_suni[SUNI_TACP_REG]; + + /* TROOLI */ + if ( SuniInt & SUNI_TROOLI ) + val = eup->eu_suni[SUNI_CLOCK_REG]; + + /* LCDI */ + /* Cleared when reading Master Interrupt Status Reg */ + + /* RDOOLI */ + if ( SuniInt & SUNI_RDOOLI ) + val = eup->eu_suni[SUNI_CLOCK_REG]; + + return; +} + +/* + * Device interrupt routine + * + * Service an interrupt from this device + * + * Arguments: + * eup pointer to device unit structure + * + * Returns: + * none + * + */ +#if defined(BSD) && BSD < 199506 +int +#else +void +#endif +eni_intr ( arg ) + void *arg; +{ + Eni_unit *eup = (Eni_unit *)arg; +#if defined(BSD) && BSD < 199506 + int serviced = 1; +#endif /* BSD < 199506 */ + + /* + * Read and acknowledge any interrupts + */ + u_long mask = eup->eu_midway[MIDWAY_ISA]; + /* + * Read the error statistics counter + */ + u_long sval = eup->eu_midway[MIDWAY_STAT]; + + /* + * Update statistics from adapter + */ + eup->eu_trash += ( sval >> 16 ); + eup->eu_ovfl += ( sval & 0xffff ); + + /* + * We handle any DMA completes first so + * that we can free resources for use + * during transmit and especially receive + */ + /* + * Handle RX DMA Complete + */ + if ( mask & ENI_INT_RX_DMA ) { + eni_recv_drain ( eup ); + } + + /* + * Handle TX DMA Complete + */ + if ( mask & ENI_INT_TX_DMA ) { + eni_xmit_drain ( eup ); + } + + /* + * Look for any PDUs in service list + */ + if ( mask & ENI_INT_SERVICE ) { + eni_do_service ( eup ); + } + + /* + * Handle miscelaneous interrupts + */ + if ( mask & ENI_INT_STAT ) { /* STAT_OVFL */ + log ( LOG_INFO, "eni_intr: stat_ovfl: 0x%x\n", sval ); + } + if ( mask & ENI_INT_SUNI ) { /* SUNI_INTR */ + eni_suni_intr ( eup ); + } + if ( mask & ENI_INT_DMA_ERR ) { /* DMA Error */ + log ( LOG_ERR, + "eni_intr: DMA Error\n" ); + /* + * We don't know how to recover from DMA errors + * yet. The adapter has disabled any further + * processing and we're going to leave it like + * that. + */ +#if defined(BSD) && BSD < 199506 + return serviced; /* Leave now */ +#else + return; /* Leave now */ +#endif + } + if ( mask & ENI_INT_IDEN ) { + log ( LOG_ERR, + "eni_intr: TX DMA Ident mismatch\n" ); + /* + * Something in the TX buffer has really gotten messed + * up. Since this is most likely a driver bug, and + * the adapter has shut everything down, leave it + * like that. + */ +#if BSD < 199506 + return 0; /* Leave now */ +#else + return; /* Leave now */ +#endif + } + if ( mask & ENI_INT_DMA_OVFL ) + eup->eu_stats.eni_st_drv.drv_xm_dmaovfl++; + if ( mask & ENI_INT_DMA_LERR ) { + log ( LOG_ERR, + "eni_intr: DMA LERR\n" ); +#if BSD < 199506 + return 0; +#else + return; +#endif + } + +#if BSD < 199506 + return 0; +#else + return; +#endif +} + diff --git a/sys/dev/hea/eni_receive.c b/sys/dev/hea/eni_receive.c new file mode 100644 index 0000000..097f297 --- /dev/null +++ b/sys/dev/hea/eni_receive.c @@ -0,0 +1,871 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: eni_receive.c,v 1.13 1998/08/07 22:14:13 mks Exp $ + * + */ + +/* + * Efficient ENI Adapter Support + * ----------------------------- + * + * Receive management + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: eni_receive.c,v 1.13 1998/08/07 22:14:13 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <dev/hea/eni_stats.h> +#include <dev/hea/eni.h> +#include <dev/hea/eni_var.h> + +static void eni_recv_stack __P((void *, KBuffer *)); + +#ifdef DIAGNOSTIC +extern int eni_pdu_print; +#endif + +/* + * Procedure to remove VCs from the Service List and generate DMA + * requests to move the associated PDUs into host memory. As PDUs + * are completed in adapter memory, the adapter examines the IN_SERVICE + * bit for the VC in the VC table. If this bit is not set, the adapter + * will place the VC number at the end of the service list queue, set + * the IN_SERVICE bit in the VC table, and interrupt the host. The host + * will remove VCs from the service list, clear the IN_SERVICE bit in + * the VC table, and create a DMA list to move the PDU into host buffers. + * + * Arguments: + * eup pointer to per unit structure + * + * Returns: + * none + * + */ +void +eni_do_service ( eup ) + Eni_unit *eup; +{ + int vcc; + Eni_vcc *evp; + u_long servwrite; + VCI_Table *vct; + u_long rdptr; + u_long *rxp; + KBuffer *m; + u_long dma[TEMP_DMA_SIZE]; + u_long i, j; + u_long dma_rd, dma_wr; + u_long dma_avail; + int pdulen; + int mask; + u_long *upp; + + /* + * Where is the adapter currently inserting entries? + */ + servwrite = eup->eu_midway[MIDWAY_SVCWR] & SVC_SIZE_MASK; + /* + * As long as we're not caught up with the adapter, keep + * removing VCs from the service list. + */ + while ( servwrite != eup->eu_servread ) { + int vci_hdr; + u_long descr; + + /* + * Get VC number and find VC table entry. + */ + vcc = eup->eu_svclist[eup->eu_servread]; + vct = &eup->eu_vcitbl[vcc]; + vci_hdr = vct->vci_control; /* Current status */ + + /* + * Check that this VCC still needs servicing. We + * might have closed this VCC down in between + * the adapter setting the flag and our checking + * the flag. Also check that we haven't placed the + * VCC into TRASH mode. + */ + if ( ( vci_hdr & VCI_IN_SERVICE ) == 0 || + ( vci_hdr & ~VCI_MODE_MASK == + VCI_MODE_TRASH << VCI_MODE_SHIFT ) ) + goto next_vcc; + + /* + * Find the size of this VCs buffer + */ + mask = (vci_hdr >> VCI_SIZE_SHIFT) & VCI_SIZE_MASK; + mask = 1 << (ENI_LOC_PREDIV + mask); + /* Turn byte count into word count */ + mask >>= 2; + /* + * Find the start of the adapter buffer for this VC. + */ + rxp = (u_long *) + ((int)(((vci_hdr >> VCI_LOC_SHIFT ) & VCI_LOC_MASK) + << ENI_LOC_PREDIV) + (int)eup->eu_ram); + /* + * Locate incoming VCC for this PDU and find where we + * should next read from. + */ + evp = (Eni_vcc *) atm_dev_vcc_find ( (Cmn_unit *)eup, + 0, vcc, VCC_IN ); + if ( evp == (Eni_vcc *)NULL ) + goto next_vcc; /* VCI no longer active */ + rdptr = evp->ev_rxpos; + /* + * Find out where the adapter is currently reassembling. + * The PDU which starts at descr is not yet complete so we + * must stop there. + */ + descr = ( vct->vci_descr >> 16 ) & 0x7FFF; + /* + * As long as we haven't processed all the completed PDUs on + * this VC, keep going... + */ + while ( rdptr != descr ) + { + int n_cells; + int pdu_descr; + int aal5; + + /* + * Ensure that the following are reset for every new + * PDU. + */ + upp = NULL; + m = NULL; + + /* + * Fisrt build a DMA with JK to skip the descriptor word. + * We must always skip the descriptor even if it turns out + * that there isn't any PDU here. + */ + j = 0; + dma[j++] = (((rdptr + 1) & (mask-1)) << DMA_COUNT_SHIFT ) | + ( vcc << DMA_VCC_SHIFT ) | DMA_JK; + dma[j++] = 0; + + /* + * We'll use some of the values below for skipping + * bad PDUs or counting statistics so compute them + * now. + */ + + /* + * Grab a copy of the descriptor word + */ + pdu_descr = rxp[rdptr]; + + /* + * Strip out cell count from descriptor word. + * At this point, we still don't know if there + * is any real data until after we check for + * TRASH mode. + */ + n_cells = pdu_descr & DESCR_CELL_COUNT; + + /* + * Is this an AAL5 PDU? Check MODE in vci_hdr. + */ + aal5 = ( ( vci_hdr & ~VCI_MODE_MASK ) == + VCI_MODE_AAL5 << VCI_MODE_SHIFT ); + + /* + * Now check to see if we're trashing on this vcc. + * If so, there is no data with this VC and the + * next word after the current descriptor is the + * descriptor for the next PDU. + */ + if ( ( pdu_descr & DESCR_TRASH_BIT ) != 0 ) { + if ( aal5 ) + /* + * Count as number of AAL5 cells dropped + */ + eup->eu_stats.eni_st_aal5.aal5_drops += n_cells; + else + /* + * Count as number of AAL0 cells dropped + */ + eup->eu_stats.eni_st_aal0.aal0_drops += n_cells; + eup->eu_pif.pif_ierrors++; + /* + * When cells have been trashed, all we have in the + * buffer is a descriptor word. There are no data + * words. Set the number of cells to zero so that + * we correctly skip to the next word which will + * be the descriptor for the next PDU. + */ + n_cells = 0; + /* + * Go issue the DMA to skip this descriptor word. + */ + goto send_dma; + } + + /* + * Data length: number of cells * cell size + */ + pdulen = n_cells * BYTES_PER_CELL; + + /* + * If this is an AAL5 PDU, then we need to check + * for the presence of any CRC errors. If there + * is one or more CRC errors, then we are going to + * drop this PDU. + */ + if ( aal5 && ( pdu_descr & DESCR_CRC_ERR ) ) { + /* + * Count the stat + */ + eup->eu_pif.pif_ierrors++; + eup->eu_stats.eni_st_aal5.aal5_pdu_crc++; + if ( evp->ev_connvc->cvc_vcc ) + evp->ev_connvc->cvc_vcc->vc_ierrors++; + /* + * Build a DMA entry to skip the rest of this + * PDU. + */ + dma[j++] = + (((rdptr + n_cells*WORDS_PER_CELL + 1) + & (mask-1)) << DMA_COUNT_SHIFT ) | + (vcc << DMA_VCC_SHIFT ) | DMA_JK; + dma[j++] = 0; + /* + * All done with this PDU. Get a buffer to save some + * data for reclamation services. + */ + KB_ALLOCPKT ( m, ENI_SMALL_BSIZE, KB_F_NOWAIT, + KB_T_DATA ); + if ( m ) { + u_long *up; + + KB_DATASTART ( m, up, u_long * ); + /* + * Indicate no PDU + */ + KB_PLENSET ( m, 0 ); + /* + * Set buffer length - only driver overhead + */ + KB_LEN ( m ) = 3 * sizeof ( u_long ); + /* + * Insert vcc, space for DMA pointers, + * and pdulen + */ + *up++ = vcc; + upp = up; /* Remember location */ + up++; /* And skip it */ + /* - to be filled later */ + *up = pdulen; /* Actual PDU length if it */ + /* were valid */ + } else { + /* + * We've a real problem here as now we can't + * reclaim/advance resources/safety pointers. + */ + eup->eu_stats.eni_st_drv.drv_rv_norsc++; +#ifdef DO_LOG + log ( LOG_ERR, + "eni_do_service: No drain buffers available. Receiver about to lock.\n" ); +#endif + } + goto send_dma; + } + + /* + * Do we need to strip the AAL layer? Yes if this + * is an AAL5 PDU. + */ + if ( aal5 ) { + /* + * Grab the CS-PDU length. Find the address of the + * last word, back up one word to skip CRC, and + * then mask the whole thing to handle circular wraps. + */ + pdulen = rxp[(rdptr + n_cells*WORDS_PER_CELL - 1) + & (mask-1)] + & 0xFFFF; + } + + /* + * We now have a valid PDU of some length. Build + * the necessary DMA list to move it into host + * memory. + */ + + /* + * Get an initial buffer. + */ + KB_ALLOCPKT ( m, ENI_SMALL_BSIZE, KB_F_NOWAIT, KB_T_DATA ); + /* + * Do we have a valid buffer? + */ + if ( m != (KBuffer *)NULL ) + { + int len; + u_long *up; + KBuffer *m0; + + KB_DATASTART ( m, up, u_long * ); + /* + * Fill in pdulen in PKTHDR structure (for IP). + */ + KB_PLENSET ( m, pdulen ); + /* + * We're going to save the VCI nuber, the start + * and stop DMA pointers, and the PDU length at + * the head of the buffer. We'll pull this out + * later after the DMA has completed. + * + * Insert VCI number as first word in first buffer, + * remeber where we want to store the start/stop + * pointers, and store the PDU length. + */ + *up++ = vcc; /* PDU's VCC */ + upp = up; /* Remember where we are */ + up++; /* To stuff start/stop pointers in */ + *up++ = pdulen; /* PDU's length */ + /* + * Leave some extra room in case a higher protocol + * (IP) wants to do a pullup. Maybe we can keep + * someone from having to allocate another buffer + * a do a larger memory copy. + */ + len = MIN ( ENI_SMALL_BSIZE, pdulen ); + (void) eni_set_dma ( eup, 1, dma, TEMP_DMA_SIZE, &j, + vcc, (u_long)up, len ); + /* + * Adjust length of remaining data in PDU + */ + pdulen -= len; + /* + * Set buffer length, including our overhead + */ + KB_LEN ( m ) = len + 3 * sizeof ( u_long ); + /* + * Finish by moving anything which won't fit in + * first buffer + */ + m0 = m; + while ( pdulen ) { + KBuffer *m1; + u_long data_addr; + + /* + * Get another buffer + */ + KB_ALLOCEXT ( m1, ENI_LARGE_BSIZE, KB_F_NOWAIT, + KB_T_DATA ); + + /* + * If we succeeded... + */ + if ( m1 ) { + /* + * Figure out how much we can move into + * this buffer. + */ + len = MIN ( ENI_LARGE_BSIZE, pdulen ); + /* + * Setup DMA list for this buffer + */ + KB_DATASTART ( m1, data_addr, u_long ); + (void) eni_set_dma + ( eup, 1, dma, TEMP_DMA_SIZE, &j, vcc, + data_addr, len ); + /* + * Adjust remaining length + */ + pdulen -= len; + /* + * Set buffer length + */ + KB_LEN ( m1 ) = len; + /* + * Link new buffer onto end and advance + * pointer + */ + KB_NEXT ( m0 ) = m1; + m0 = m1; + } else { + /* + * Either we were unable to grab another + * buffer or there are no large buffers + * available. We know that the first + * buffer is valid, so drop everything + * else, build a JK DMA to skip/drop this + * PDU, set the pointers to reclaim + * resources/advance pointers, and + * finish this PDU now. + */ + if ( KB_NEXT ( m ) ) + KB_FREEALL ( KB_NEXT ( m ) ); + eup->eu_pif.pif_ierrors++; + j = 2; + dma[j++] = + (((rdptr + n_cells*WORDS_PER_CELL + 1) + & (mask-1)) << DMA_COUNT_SHIFT ) | + (vcc << DMA_VCC_SHIFT ) | + DMA_JK; + dma[j++] = 0; + /* + * Reset PDU length to zero + */ + KB_PLENSET ( m, 0 ); + /* + * Count some statistics + */ + /* + * Count this as dropped cells + */ + if ( aal5 ) { + eup->eu_stats.eni_st_aal5.aal5_drops += + n_cells; + eup->eu_stats.eni_st_aal5.aal5_pdu_drops++; + } else + eup->eu_stats.eni_st_aal0.aal0_drops += + n_cells; + /* + * Drop it + */ + goto send_dma; + } + } + /* + * If necessary, skip AAL layer + */ + if ( aal5 ) { + dma[j++] = + (((rdptr + n_cells*WORDS_PER_CELL + 1) + & (mask-1)) << DMA_COUNT_SHIFT) + | (vcc << DMA_VCC_SHIFT) | DMA_JK; + dma[j++] = 0; + } + } else { + /* + * We failed to get an initial buffer. Since we + * haven't changed anything for this PDU yet and the + * PDU is still valid, exit now and try to service it + * next time around. We're not very likely to get + * another buffer right now anyways. + */ + eup->eu_stats.eni_st_drv.drv_rv_nobufs++; +#ifdef DO_LOG + log ( LOG_ERR, +"eni_do_service: No buffers available. Exiting without servicing service list.\n" ); +#endif + /* + * Clear the IN_SERVICE indicator for this VCC + */ + vct->vci_control &= ~VCI_IN_SERVICE; + return; + } + +send_dma: + /* + * Set the end bit on the last DMA for this PDU + */ + dma[j-2] |= DMA_END_BIT; + + /* + * Where are the current DMA pointers + */ + dma_rd = eup->eu_midway[MIDWAY_RX_RD]; + dma_wr = eup->eu_midway[MIDWAY_RX_WR]; + + /* + * Check how much space is available + */ + if ( dma_rd == dma_wr ) + dma_avail = DMA_LIST_SIZE; + else + dma_avail = ( dma_rd + DMA_LIST_SIZE - dma_wr ) + & (DMA_LIST_SIZE-1); + + /* + * Check for queue full or wrap past write okay pointer + */ + if ( dma_avail < j || + ( dma_wr + j > eup->eu_rxdmawr + DMA_LIST_SIZE ) ) { + /* + * There's no room in the DMA list to insert + * this request. Since we haven't changed anything + * yet and the PDU is good, exit now and service + * it next time around. What we really need to do + * is wait for the RX list to drain and that won't + * happen if we keep trying to process PDUs here. + */ + eup->eu_stats.eni_st_drv.drv_rv_nodma++; +#ifdef DO_LOG + log ( LOG_ERR, +"eni_do_service: No room in receive DMA list. Postponing service request.\n" ); +#endif + /* + * Free the local buffer chain + */ + KB_FREEALL ( m ); + /* + * Clear the IN_SERVICE indicator for this VCC. + */ + vct->vci_control &= ~VCI_IN_SERVICE; + return; + } + + /* + * If we have a buffer chain, save the starting + * dma_list location. + */ + if ( upp ) { + *upp = dma_wr << 16; + } + + /* + * Stuff the DMA list + */ + j >>= 1; + for ( i = 0; i < j; i++ ) { + eup->eu_rxdma[dma_wr*2] = dma[i*2]; + eup->eu_rxdma[dma_wr*2+1] = dma[i*2+1]; + dma_wr = (dma_wr+1) & (DMA_LIST_SIZE-1); + } + /* + * If we have a buffer chain, save the location of + * the ending dma_list location and queue the chain + * so that we can recover the resources later. + */ + if ( upp ) { + *upp |= dma_wr; + /* + * Place buffer on receive queue waiting for RX_DMA + */ + if ( IF_QFULL ( &eup->eu_rxqueue ) ) { + /* + * We haven't done anything we can't back out + * of. Drop request and service it next time. + * We've inserted the DMA list but it's not + * valid until we advance the RX_WR pointer, + * thus it's okay to bail here... + */ + eup->eu_stats.eni_st_drv.drv_rv_rxq++; +#ifdef DO_LOG + log ( LOG_ERR, + "eni_do_service: RX drain queue full. Postponing servicing.\n" ); +#endif + KB_FREEALL ( m ); + /* + * Clear the IN_SERVICE indicator for this VCC. + */ + vct->vci_control &= ~VCI_IN_SERVICE; + return; + } else { + IF_ENQUEUE ( &eup->eu_rxqueue, m ); + /* + * Advance the RX_WR pointer to cause + * the adapter to work on this DMA list. + */ + eup->eu_midway[MIDWAY_RX_WR] = dma_wr; + } + } + /* + * Advance our notion of where the next PDU + * should start. + */ + rdptr = (rdptr + n_cells*WORDS_PER_CELL + 1) + & (mask-1); + evp->ev_rxpos = rdptr; + + /* + * Increment cells/pdu received stats. + */ + eup->eu_stats.eni_st_atm.atm_rcvd += n_cells; + if ( aal5 ) { + eup->eu_stats.eni_st_aal5.aal5_rcvd += n_cells; + eup->eu_stats.eni_st_aal5.aal5_pdu_rcvd++; + } else { + eup->eu_stats.eni_st_aal0.aal0_rcvd += n_cells; + } + + /* + * Continue processing PDUs on this same VCI + */ + } + +next_vcc: + /* + * Advance to next entry in the service_list. + */ + eup->eu_servread = (eup->eu_servread + 1) & SVC_SIZE_MASK; + + /* + * And clear the IN_SERVICE indicator for this VCC. + */ + vct->vci_control &= ~VCI_IN_SERVICE; + } + return; +} + +/* + * Drain Receive queue + * + * As we build DMA lists to move PDUs from adapter buffers into host + * buffers, we place the request on a private ifqueue so that we can + * free any resources AFTER we know they've been successfully DMAed. + * As part of the service processing, we record the PDUs start and stop + * entries in the DMA list, and prevent wrapping. When we pull the top + * entry off, we simply check that the current DMA location is outside + * this PDU and if so, it's okay to free things. + * + * Arguments: + * eup pointer to device unit structure + * + * Returns: + * none + * + */ +void +eni_recv_drain ( eup ) + Eni_unit *eup; +{ + KBuffer *m; + Eni_vcc *evp; + struct vccb *vcp; + u_long vcc; + u_long DMA_Rdptr; + u_long dma_wrp; + u_long start, stop; + int que = 0; + int s; + + s = splimp(); + /* Pop first buffer */ + IF_DEQUEUE ( &eup->eu_rxqueue, m ); + while ( m ) { + u_long *up; + u_long pdulen; + + KB_DATASTART ( m, up, u_long * ); + + /* + * Grab the VCI number + */ + vcc = *up++; + + /* + * Check to see if we can process this buffer yet. + */ + /* Get current DMA_Rdptr */ + DMA_Rdptr = eup->eu_midway[MIDWAY_RX_RD]; + /* Boundaries for first buffer */ + dma_wrp = *up++; + start = dma_wrp >> 16; + stop = dma_wrp & 0xffff; + /* + * Start should not equal stop because that would + * mean we tried inserting a NULL DMA list. + */ + if ( start > stop ) { /* We wrapped */ + if ( !(DMA_Rdptr >= stop && DMA_Rdptr < start) ) { + IF_PREPEND ( &eup->eu_rxqueue, m ); + goto finish; + } + } else { + if ( DMA_Rdptr < stop && DMA_Rdptr >= start ) { + IF_PREPEND ( &eup->eu_rxqueue, m ); + goto finish; + } + } + /* + * Adapter is finished with this buffer, we can + * continue processing it now. + */ + + /* + * Locate incoming VCC for this PDU + */ + evp = (Eni_vcc *) atm_dev_vcc_find ( (Cmn_unit *)eup, + 0, vcc, VCC_IN ); + + if ( evp == NULL ) { + eup->eu_stats.eni_st_drv.drv_rv_novcc++; + KB_FREEALL ( m ); + goto next_buffer; + } + +#ifdef DIAGNOSTIC + if ( eni_pdu_print ) + atm_dev_pdu_print ( (Cmn_unit *)eup, (Cmn_vcc *)evp, m, + "eni_stack_drain" ); +#endif + + /* + * Grab theoretical PDU length + */ + pdulen = *up++; + + /* + * Quick, count the PDU + */ + eup->eu_pif.pif_ipdus++; + eup->eu_pif.pif_ibytes += pdulen; + if ( evp ) { + vcp = evp->ev_connvc->cvc_vcc; + if ( vcp ) { + vcp->vc_ipdus++; + vcp->vc_ibytes += pdulen; + if ( vcp->vc_nif ) { + vcp->vc_nif->nif_ibytes += pdulen; + vcp->vc_nif->nif_if.if_ipackets++; +#if (defined(BSD) && (BSD >= 199103)) + vcp->vc_nif->nif_if.if_ibytes += pdulen; +#endif + } + } + } + + /* + * Advance DMA write allowable pointer + */ + eup->eu_rxdmawr = stop; + + /* + * Get packet PDU length + */ + KB_PLENGET ( m, pdulen ); + + /* + * Only try queueing this if there is data + * to be handed up to the next layer. Errors + * such as CRC and VC trashing will get us this + * far to advance pointers, etc., but the PDU + * length will be zero. + */ + if ( pdulen ) { + /* + * We saved three words back in eni_do_service() + * to use for callback. Since the core only + * expects two words, skip over the first one. + * Then, reset up pointer to start of buffer data + * area and write the callback info. + */ + KB_HEADADJ ( m, -sizeof(u_long) ); + KB_DATASTART ( m, up, u_long * ); + *((int *)up) = (int)eni_recv_stack; + up++; + *((int *)up) = (int)evp; + /* + * Schedule callback + */ + if ( !IF_QFULL ( &atm_intrq ) ) { + que++; + IF_ENQUEUE ( &atm_intrq, m ); + } else { + eup->eu_stats.eni_st_drv.drv_rv_intrq++; + eup->eu_pif.pif_ierrors++; +#ifdef DO_LOG + log ( LOG_ERR, +"eni_receive_drain: ATM_INTRQ is full. Unable to pass up stack.\n" ); +#endif + KB_FREEALL ( m ); + } + } else { + /* + * Free zero-length buffer + */ + KB_FREEALL(m); + } + +next_buffer: + /* + * Look for next buffer + */ + IF_DEQUEUE ( &eup->eu_rxqueue, m ); + } +finish: + (void) splx(s); + + /* + * If we found any completed buffers, schedule a call into + * the kernel to process the atm_intrq. + */ + if ( que ) + SCHED_ATM; + + return; + +} + +/* + * Pass incoming PDU up Stack + * + * This function is called via the core ATM interrupt queue callback + * set in eni_recv_drain(). It will pass the supplied incoming + * PDU up the incoming VCC's stack. + * + * Arguments: + * tok token to identify stack instantiation + * m pointer to incoming PDU buffer chain + * + * Returns: + * none + */ +static void +eni_recv_stack ( tok, m ) + void *tok; + KBuffer *m; +{ + Eni_vcc *evp = (Eni_vcc *)tok; + int err; + + /* + * This should never happen now but if it does and we don't stop it, + * we end up panic'ing in netatm when trying to pull a function + * pointer and token value out of a buffer with address zero. + */ + if ( !m ) { +#ifdef DO_LOG + log ( LOG_ERR, + "eni_recv_stack: NULL buffer, tok = 0x%x\n", tok ); +#endif + return; + } + + /* + * Send the data up the stack + */ + STACK_CALL ( CPCS_UNITDATA_SIG, evp->ev_upper, + (void *)evp->ev_toku, evp->ev_connvc, (int)m, 0, err ); + if ( err ) { + KB_FREEALL ( m ); + } + + return; +} + diff --git a/sys/dev/hea/eni_stats.h b/sys/dev/hea/eni_stats.h new file mode 100644 index 0000000..1f2a413 --- /dev/null +++ b/sys/dev/hea/eni_stats.h @@ -0,0 +1,134 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: eni_stats.h,v 1.6 1998/08/26 23:28:54 mks Exp $ + * + */ + +/* + * Efficient ENI Adapter Support + * ----------------------------- + * + * Defines for statistics + * + */ + +#ifndef _ENI_ENI_STATS_H +#define _ENI_ENI_STATS_H + +struct eni_stats_oc3 { + u_long oc3_sect_bip8; /* Section 8-bit intrlv parity errors */ + u_long oc3_path_bip8; /* Path 8-bit intrlv parity errors */ + u_long oc3_line_bip24; /* Line 24-bit intrlv parity errors */ + u_long oc3_line_febe; /* Line far-end block errors */ + u_long oc3_path_febe; /* Path far-end block errors */ + u_long oc3_hec_corr; /* Correctable HEC errors */ + u_long oc3_hec_uncorr; /* Uncorrectable HEC errors */ + u_long oc3_pad; /* Pad to quad-word boundary */ +}; +typedef struct eni_stats_oc3 Eni_Stats_oc3; + +struct eni_stats_atm { + u_long atm_xmit; /* Cells transmitted */ + u_long atm_rcvd; /* Cells received */ + u_long atm_pad[2]; /* Pad to quad-word boundary */ +}; +typedef struct eni_stats_atm Eni_Stats_atm; + +struct eni_stats_aal0 { + u_long aal0_xmit; /* Cells transmitted */ + u_long aal0_rcvd; /* Cells received */ + u_long aal0_drops; /* Cells dropped */ + u_long aal0_pad; /* Pad to quad-word boundary */ +}; +typedef struct eni_stats_aal0 Eni_Stats_aal0; + +struct eni_stats_aal5 { + u_long aal5_xmit; /* Cells transmitted */ + u_long aal5_rcvd; /* Cells received */ + u_long aal5_crc_len; /* Cells with CRC/length errors */ + u_long aal5_drops; /* Cell drops */ + u_long aal5_pdu_xmit; /* CS PDUs transmitted */ + u_long aal5_pdu_rcvd; /* CS PDUs received */ + u_long aal5_pdu_crc; /* CS PDUs with CRC errors */ + u_long aal5_pdu_errs; /* CS layer protocol errors */ + u_long aal5_pdu_drops; /* CS PDUs dropped */ + u_long aal5_pad[3]; /* Pad to quad-word boundary */ +}; +typedef struct eni_stats_aal5 Eni_Stats_aal5; + +struct eni_stats_driver { + /* + * Adapter memory allocator stats + */ + u_long drv_mm_toobig; /* Size larger then adapter supports */ + u_long drv_mm_nodesc; /* No memory area descriptor avail */ + u_long drv_mm_nobuf; /* No memory buffer available */ + u_long drv_mm_notuse; /* Calling free() on free buffer */ + u_long drv_mm_notfnd; /* Couldn't find descr for free() */ + + /* + * VCM sats + */ + u_long drv_vc_maxpdu; /* Requested PDU size too large */ + u_long drv_vc_badrng; /* VPI and/or VCI too large */ + + /* + * Receive stats + */ + u_long drv_rv_norsc; /* No buffer for resource pointers */ + u_long drv_rv_nobufs; /* No buffers for PDU */ + u_long drv_rv_nodma; /* No room in RXDMA list */ + u_long drv_rv_rxq; /* No room in local rxqueue */ + u_long drv_rv_novcc; /* Draining PDU on closed VCC */ + u_long drv_rv_intrq; /* No room in atm_intrq */ + u_long drv_rv_null; /* Trying to pass null PDU up stack */ + u_long drv_rv_segdma; /* No DMA address */ + + /* + * Transmit stats + */ + u_long drv_xm_segdma; /* No DMA address */ + u_long drv_xm_segnoal; /* Non-aligned segment */ + u_long drv_xm_seglen; /* Padded length segment */ + u_long drv_xm_maxpdu; /* Too many segments - dropped */ + u_long drv_xm_nobuf; /* No space in TX buffer - dropped */ + u_long drv_xm_norsc; /* No buffers for resource pointers */ + u_long drv_xm_nodma; /* No space in TXDMA list */ + u_long drv_xm_dmaovfl; /* DMA overflow */ + +}; +typedef struct eni_stats_driver Eni_Stats_drv; + +struct eni_stats { + Eni_Stats_oc3 eni_st_oc3; /* OC3 layer stats */ + Eni_Stats_atm eni_st_atm; /* ATM layer stats */ + Eni_Stats_aal0 eni_st_aal0; /* AAL0 layer stats */ + Eni_Stats_aal5 eni_st_aal5; /* AAL5 layer stats */ + Eni_Stats_drv eni_st_drv; /* Driver stats */ +}; +typedef struct eni_stats Eni_stats; + +#endif /* _ENI_ENI_STATS_H */ diff --git a/sys/dev/hea/eni_suni.h b/sys/dev/hea/eni_suni.h new file mode 100644 index 0000000..3a0b0f7 --- /dev/null +++ b/sys/dev/hea/eni_suni.h @@ -0,0 +1,78 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: eni_suni.h,v 1.2 1997/05/06 22:08:17 mks Exp $ + * + */ + +/* + * Efficient ENI Adapter Support + * ----------------------------- + * + * Defines for SUNI chip + * + */ + +#ifndef _ENI_ENI_SUNI_H +#define _ENI_ENI_SUNI_H + +/* + * Interrupt bits in SUNI Master Interrupt Status Reg + */ +#define SUNI_RSOPI 0x01 +#define SUNI_RLOPI 0x02 +#define SUNI_RPOPI 0x04 +#define SUNI_RACPI 0x08 +#define SUNI_TACPI 0x10 +#define SUNI_RDOOLI 0x20 +#define SUNI_LCDI 0x40 +#define SUNI_TROOLI 0x80 + +/* + * SUNI Register numbers + */ +#define SUNI_MASTER_REG 0x00 /* Master reset and ID */ +#define SUNI_IS_REG 0x02 /* Master Interrupt Status */ +#define SUNI_CLOCK_REG 0x06 /* Clock synth/control/status */ +#define SUNI_RSOP_REG 0x10 /* RSOP control/Interrupt Status */ +#define SUNI_SECT_BIP_REG 0x12 +#define SUNI_RLOP_REG 0x18 /* RLOP control/Interrupt Status */ +#define SUNI_LINE_BIP_REG 0x1A +#define SUNI_LINE_FEBE_REG 0x1D +#define SUNI_RPOP_IS_REG 0x31 /* RPOP Interrupt Status */ +#define SUNI_PATH_BIP_REG 0x38 +#define SUNI_PATH_FEBE_REG 0x3A +#define SUNI_RACP_REG 0x50 /* RACP control/status */ +#define SUNI_HECS_REG 0x54 +#define SUNI_UHECS_REG 0x55 +#define SUNI_TACP_REG 0x60 /* TACP control/status */ + +/* + * Delay timer to allow SUNI statistic registers to load + */ +#define SUNI_DELAY 10 + +#endif /* _ENI_ENI_SUNI_H */ + diff --git a/sys/dev/hea/eni_transmit.c b/sys/dev/hea/eni_transmit.c new file mode 100644 index 0000000..25066df --- /dev/null +++ b/sys/dev/hea/eni_transmit.c @@ -0,0 +1,823 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: eni_transmit.c,v 1.20 1998/07/17 20:20:16 root Exp $ + * + */ + +/* + * Efficient ENI Adapter Support + * ----------------------------- + * + * Transmit queue management and PDU output processing + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: eni_transmit.c,v 1.20 1998/07/17 20:20:16 root Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <dev/hea/eni_stats.h> +#include <dev/hea/eni.h> +#include <dev/hea/eni_var.h> + +/* + * Make a variable which controls printing of PDUs + * as they travel through the driver. + */ +#ifdef DIAGNOSTIC +int eni_pdu_print = 0; +#endif + +/* + * Some PCI chipsets do not handle one or more of the 8WORD or + * 4WORD DMA transfer sizes. Default to using only 1WORD transfer + * sizes unless the user wishes to experiment. + * + * Make sure that these have to be changed here in this module. + */ +#define DMA_USE_8WORD +#define DMA_USE_4WORD + +/* + * Create a DMA list entry + * + * DMA entries consist of a control word and a physical address. + * Control words are comprised of a DMA type, a count of type transfers + * to occur, and a variable which for TX requests is the TX channel + * number and for RX requests is the VCC number. + * + * Arguments: + * eup pointer to unit structure + * rx set if receiving + * dma_list pointer to DMA list structure + * list_size length of DMA list structure + * idx pointer to current list entry + * val TX channel or RX vcc + * addr virtual DMA address of data buffer + * size size in bytes of DMA request to be built + * + * Returns: + * dma_list updated with new entries + * idx points to next list entry + * -1 no room in DMA list structure or DMA_GET_ADDR failed + */ +int +eni_set_dma ( eup, rx, dma_list, list_size, idx, val, addr, size ) +Eni_unit *eup; +u_long *dma_list; +int list_size; +long *idx; +int val; +u_long addr; +int size; +{ + int dsize; /* Size of current DMA request */ + + /* + * Round up to multiple of word and convert to number + * of words rather then number of bytes. + */ + size = ( size + 3 ) >> 2; + +#ifdef DMA_USE_8WORD + /* + * Check for room in DMA list - we need two entires + */ + if ( *idx + 2 >= list_size ) + return ( -1 ); + + /* + * Here is the big win. Move as much data possible with + * n 8WORD DMAs. + */ + /* + * Check if we can do one or more 8WORD DMAs + */ + dsize = size & ~7; + if ( dsize ) { + dma_list[(*idx)++] = ( dsize >> 3 ) << DMA_COUNT_SHIFT | + val << DMA_VCC_SHIFT | DMA_8WORD; + dma_list[*idx] = (u_long)DMA_GET_ADDR ( addr, dsize, 0, 0 ); + if ( dma_list[*idx] == NULL ) { + if ( rx ) + eup->eu_stats.eni_st_drv.drv_rv_segdma++; + else + eup->eu_stats.eni_st_drv.drv_xm_segdma++; + return ( -1 ); /* DMA_GET_ADDR failed */ + } else + (*idx)++; /* increment index */ + /* + * Adjust addr and size + */ + addr += dsize << 2; + size &= 7; + } +#endif /* DMA_USE_8WORD */ + +#ifdef DMA_USE_4WORD + /* + * Check for room in DMA list - we need two entries + */ + if ( *idx + 2 >= list_size ) + return ( -1 ); + + /* + * Kindof a tossup from this point on. Since we hacked as many + * 8WORD DMAs off as possible, we are left with 0-7 words + * of remaining data. We could do upto one 4WORD with 0-3 + * words left, or upto three 2WORDS with 0-1 words left, + * or upto seven WORDS with nothing left. Someday we should + * experiment with performance and see if any particular + * combination is a better win then some other... + */ + /* + * Check if we can do one or more 4WORD DMAs + */ + dsize = size & ~3; + if ( dsize ) { + dma_list[(*idx)++] = ( dsize >> 2 ) << DMA_COUNT_SHIFT | + val << DMA_VCC_SHIFT | DMA_4WORD; + dma_list[*idx] = (u_long)DMA_GET_ADDR ( addr, dsize, 0, 0 ); + if ( dma_list[*idx] == NULL ) { + if ( rx ) + eup->eu_stats.eni_st_drv.drv_rv_segdma++; + else + eup->eu_stats.eni_st_drv.drv_xm_segdma++; + return ( -1 ); /* DMA_GET_ADDR failed */ + } else + (*idx)++; /* increment index */ + /* + * Adjust addr and size + */ + addr += dsize << 2; + size &= 3; + } +#endif /* DMA_USE_4WORD */ + + /* + * Check for room in DMA list - we need two entries + */ + if ( *idx + 2 >= list_size ) + return ( -1 ); + + /* + * Hard to know if one 2WORD and 0/1 WORD DMA would be better + * then 2/3 WORD DMAs. For now, skip 2WORD DMAs in favor of + * WORD DMAs. + */ + + /* + * Finish remaining size a 1WORD DMAs + */ + if ( size ) { + dma_list[(*idx)++] = ( size ) << DMA_COUNT_SHIFT | + val << DMA_VCC_SHIFT | DMA_WORD; + dma_list[*idx] = (u_long)DMA_GET_ADDR ( addr, size, 0, 0 ); + if ( dma_list[*idx] == NULL ) { + if ( rx ) + eup->eu_stats.eni_st_drv.drv_rv_segdma++; + else + eup->eu_stats.eni_st_drv.drv_xm_segdma++; + return ( -1 ); /* DMA_GET_ADDR failed */ + } else + (*idx)++; /* increment index */ + } + + /* + * Inserted descriptor okay + */ + return 0; +} + +/* + * Drain Transmit queue + * + * As PDUs are given to the adapter to be transmitted, we + * place them into a private ifqueue so that we can free + * any resources AFTER we know they've been successfully DMAed. + * As part of the output processing, we record the PDUs start + * and stop entries in the DMA list, and prevent wrapping. When + * we pull the top element off, we simply check that the current + * DMA location is outside this PDU and if so, it's okay to free + * things. + * + * PDUs are always in ascending order in the queue. + * + * Arguments: + * eup pointer to device unit structure + * + * Returns: + * none + * + */ +void +eni_xmit_drain ( eup ) + Eni_unit *eup; +{ + KBuffer *m; + Eni_vcc *evp; + struct vccb *vcp; + u_long pdulen; + u_long start, stop; + u_long dmap; + int s = splimp(); + + /* + * Pull the top element (PDU) off + */ + IF_DEQUEUE ( &eup->eu_txqueue, m ); + /* + * As long as there are valid elements + */ + while ( m ) { + u_long *up; + + /* + * Find start of buffer + */ + KB_DATASTART ( m, up, u_long * ); + + /* + * First word is the VCC for this PDU + */ + /* + * NOTE: There is a potential problem here in that + * if the VCC is closed after this buffer was transmitted + * but before we get here, that while evp is non-null, + * it will not reference a valid vccb. We need to either + * delay closing the VCC until all references are removed + * from the drain stacks, actually go through the drain + * stacks and remove any references, or find someway of + * indicating that this vccb is nolonger usable. + */ + evp = (Eni_vcc *)*up++; + /* + * Second word is the start and stop DMA pointers + */ + start = *up >> 16; + stop = *up++ & 0xffff; + /* + * Find out where the TX engine is at + */ + dmap = eup->eu_midway[MIDWAY_TX_RD]; + /* + * Check to see if TX engine has processed this + * PDU yet. Remember that everything is circular + * and that stop might be less than start numerically. + */ + if ( start > stop ) { + if ( !(dmap >= stop && dmap < start) ) { + /* + * Haven't finished this PDU yet - replace + * it as the head of list. + */ + IF_PREPEND ( &eup->eu_txqueue, m ); + /* + * If this one isn't done, none of the others + * are either. + */ + (void) splx(s); + return; + } + } else { + if ( dmap < stop && dmap >= start ) { + /* + * Haven't finished this PDU yet - replace + * it as the head of list. + */ + IF_PREPEND ( &eup->eu_txqueue, m ); + /* + * If this one isn't done, none of the others + * are either. + */ + (void) splx(s); + return; + } + } + + /* + * Count the PDU stats for this interface + */ + eup->eu_pif.pif_opdus++; + /* + * Third word is PDU length from eni_output(). + */ + pdulen = *up++; + eup->eu_txfirst = (eup->eu_txfirst + *up) & + (eup->eu_txsize - 1); + eup->eu_pif.pif_obytes += pdulen; + + /* + * Now lookup the VCC entry and counts the stats for + * this VC. + */ + if ( evp ) { + vcp = evp->ev_connvc->cvc_vcc; + if ( vcp ) { + vcp->vc_opdus++; + vcp->vc_obytes += pdulen; + /* + * If we also have a network interface, count the PDU + * there also. + */ + if ( vcp->vc_nif ) { + vcp->vc_nif->nif_obytes += pdulen; + vcp->vc_nif->nif_if.if_opackets++; +#if (defined(BSD) && (BSD >= 199103)) + vcp->vc_nif->nif_if.if_obytes += pdulen; +#endif + } + } + } + /* + * Free the buffer chain + */ + KB_FREEALL ( m ); + + /* + * Advance DMA write okay pointer + */ + eup->eu_txdmawr = stop; + + /* + * Look for next completed transmit PDU + */ + IF_DEQUEUE ( &eup->eu_txqueue, m ); + } + /* + * We've drained the queue... + */ + (void) splx(s); + return; +} + +/* + * Output a PDU + * + * This function is called via the common driver code after receiving a + * stack *_DATA* command. The common code has already validated most of + * the request so we just need to check a few more ENI-specific details. + * Then we just build a segmentation structure for the PDU and place the + * address into the DMA_Transmit_queue. + * + * Arguments: + * cup pointer to device common unit + * cvp pointer to common VCC entry + * m pointer to output PDU buffer chain head + * + * Returns: + * none + * + */ +void +eni_output ( cup, cvp, m ) + Cmn_unit *cup; + Cmn_vcc *cvp; + KBuffer *m; +{ + Eni_unit *eup = (Eni_unit *)cup; + Eni_vcc *evp = (Eni_vcc *)cvp; + int s, s2; + int pdulen = 0; + u_long size; + u_long buf_avail; + u_long dma_rd, dma_wr; + u_long dma[TEMP_DMA_SIZE]; + int aal5, i; + long j; + u_long dma_avail; + u_long dma_start; + Eni_mem tx_send; + u_long *up; + KBuffer *m0 = m, *m1, *mprev = NULL; + caddr_t cp, bfr; + u_int len, align; + int compressed = 0; + +#ifdef DIAGNOSTIC + if ( eni_pdu_print ) + atm_dev_pdu_print ( cup, cvp, m, "eni output" ); +#endif + + /* + * Re-entry point for after buffer compression (if needed) + */ +retry: + + /* + * We can avoid traversing the buffer list twice by building + * the middle (minus header and trailer) dma list at the + * same time we massage address and size alignments. Since + * this list remains local until we determine we've enough + * room, we're not going to trash anything by not checking + * sizes, etc. yet. Skip first entry to be used later to skip + * descriptor word. + */ + j = 2; + /* + * Do data positioning for address and length alignment + */ + while ( m ) { + u_long buf_addr; /* For passing addr to eni_set_dma() */ + + /* + * Get rid of any zero length buffers + */ + if ( KB_LEN ( m ) == 0 ) { + if ( mprev ) { + KB_UNLINK ( m, mprev, m1 ); + } else { + KB_UNLINKHEAD ( m, m1 ); + m0 = m1; + } + m = m1; + continue; + } + /* + * Get start of data onto full-word alignment + */ + KB_DATASTART ( m, cp, caddr_t ); + if ( align = ((u_int)cp) & (sizeof(u_long)-1)) { + /* + * Gotta slide the data up + */ + eup->eu_stats.eni_st_drv.drv_xm_segnoal; + bfr = cp - align; + KM_COPY ( cp, bfr, KB_LEN ( m ) ); + KB_HEADMOVE ( m, -align ); + } else { + /* + * Data already aligned + */ + bfr = cp; + } + /* + * Now work on getting the data length correct + */ + len = KB_LEN ( m ); + while ( ( align = ( len & (sizeof(u_long)-1))) && + (m1 = KB_NEXT ( m ) ) ) { + + /* + * Have to move some data from following buffer(s) + * to word-fill this buffer + */ + u_int ncopy = MIN ( sizeof(u_long) - align, + KB_LEN ( m1 ) ); + + if ( ncopy ) { + /* + * Move data to current buffer + */ + caddr_t dest; + + eup->eu_stats.eni_st_drv.drv_xm_seglen++; + KB_DATASTART ( m1, cp, caddr_t ); + dest = bfr + len; + KB_HEADADJ ( m1, -ncopy ); + KB_TAILADJ ( m, ncopy ); + len += ncopy; + while ( ncopy-- ) { + *dest++ = *cp++; + } + } + + /* + * If we've drained the buffer, free it + */ + if ( KB_LEN ( m1 ) == 0 ) { + KBuffer *m2; + + KB_UNLINK ( m1, m, m2 ); + } + } + + /* + * Address and size are now aligned. Build dma list + * using TX channel 0. Also, round length up to a word + * size which should only effect the last buffer in the + * chain. This works because the PDU length is maintained + * seperately and we're not really adjusting the buffer's + * idea of its length. + */ + KB_DATASTART ( m, buf_addr, u_long ); + if ( eni_set_dma ( eup, 0, dma, TEMP_DMA_SIZE, &j, 0, + buf_addr, KB_LEN ( m ) ) < 0 ) { + /* + * Failed to build DMA list. First, we'll try to + * compress the buffer chain into a smaller number + * of buffers. After compressing, we'll try to send + * the new buffer chain. If we still fail, then + * we'll drop the pdu. + */ + if ( compressed ) { +#ifdef DO_LOG + log ( LOG_ERR, + "eni_output: eni_set_dma failed\n" ); +#endif + eup->eu_pif.pif_oerrors++; + KB_FREEALL ( m0 ); + return; + } + + eup->eu_stats.eni_st_drv.drv_xm_maxpdu++; + + m = atm_dev_compress ( m0 ); + if ( m == NULL ) { +#ifdef DO_LOG + log ( LOG_ERR, + "eni_output: atm_dev_compress() failed\n" ); +#endif + eup->eu_pif.pif_oerrors++; + return; + } + + /* + * Reset to new head of buffer chain + */ + m0 = m; + + /* + * Indicate we've been through here + */ + compressed = 1; + + /* + * Retry to build the DMA descriptors for the newly + * compressed buffer chain + */ + goto retry; + + } + + /* + * Now count the length + */ + pdulen += KB_LEN ( m ); + + /* + * Bump counters and get ready for next buffer + */ + mprev = m; + m = KB_NEXT ( m ); + } + + /* + * Get a buffer to use in a private queue so that we can + * reclaim resources after the DMA has finished. + */ + KB_ALLOC ( m, ENI_SMALL_BSIZE, KB_F_NOWAIT, KB_T_DATA ); + if ( m ) { + /* + * Link the PDU onto our new head + */ + KB_NEXT ( m ) = m0; + } else { + /* + * Drop this PDU and let the sender try again. + */ + eup->eu_stats.eni_st_drv.drv_xm_norsc++; +#ifdef DO_LOG + log(LOG_ERR, "eni_output: Unable to allocate drain buffer.\n"); +#endif + eup->eu_pif.pif_oerrors++; + KB_FREEALL ( m0 ); + return; + } + + s = splnet(); + + /* + * Calculate size of buffer necessary to store PDU. If this + * is an AAL5 PDU, we'll need to know where to stuff the length + * value in the trailer. + */ + /* + * AAL5 PDUs need an extra two words for control/length and + * CRC. Check for AAL5 and add requirements here. + */ + if (aal5 = (evp->ev_connvc->cvc_attr.aal.type == ATM_AAL5)) + size = pdulen + 2 * sizeof(long); + else + size = pdulen; + /* + * Pad to next complete cell boundary + */ + size += (BYTES_PER_CELL - 1); + size -= size % BYTES_PER_CELL; + /* + * Convert size to words and add 2 words overhead for every + * PDU (descriptor and cell header). + */ + size = (size >> 2) + 2; + + /* + * First, check to see if there's enough buffer space to + * store the PDU. We do this by checking to see if the size + * required crosses the eu_txfirst pointer. However, we don't + * want to exactly fill the buffer, because we won't be able to + * distinguish between a full and empty buffer. + */ + if ( eup->eu_txpos == eup->eu_txfirst ) + buf_avail = eup->eu_txsize; + else + if ( eup->eu_txpos > eup->eu_txfirst ) + buf_avail = eup->eu_txsize - ( eup->eu_txpos - eup->eu_txfirst ); + else + buf_avail = eup->eu_txfirst - eup->eu_txpos; + + if ( size >= buf_avail ) + { + /* + * No buffer space in the adapter to store this PDU. + * Drop PDU and return. + */ + eup->eu_stats.eni_st_drv.drv_xm_nobuf++; +#ifdef DO_LOG + log ( LOG_ERR, + "eni_output: not enough room in buffer\n" ); +#endif + eup->eu_pif.pif_oerrors++; + KB_FREEALL ( m ); + (void) splx(s); + return; + } + + /* + * Find out where current DMA pointers are at + */ + dma_start = dma_wr = eup->eu_midway[MIDWAY_TX_WR]; + dma_rd = eup->eu_midway[MIDWAY_TX_RD]; + + /* + * Figure out how much DMA room we have available + */ + if ( dma_rd == dma_wr ) { /* Queue is empty */ + dma_avail = DMA_LIST_SIZE; + } else { + dma_avail = ( dma_rd + DMA_LIST_SIZE - dma_wr ) + & ( DMA_LIST_SIZE - 1 ); + } + /* + * Check to see if we can describe this PDU or if we're: + * out of room, will wrap past recovered resources. + */ + if ( dma_avail < (j / 2 + 4) || + ( dma_wr + (j / 2 + 4) > eup->eu_txdmawr + DMA_LIST_SIZE ) ) { + /* + * No space to insert DMA list into queue. Drop this PDU. + */ + eup->eu_stats.eni_st_drv.drv_xm_nodma++; +#ifdef DO_LOG + log ( LOG_ERR, + "eni_output: not enough room in DMA queue\n" ); +#endif + eup->eu_pif.pif_oerrors++; + KB_FREEALL( m ); + (void) splx(s); + return; + } + + /* + * Create DMA descriptor for header. There is a descriptor word + * and also a cell header word which we'll set manually. + */ + dma[0] = (((int)(eup->eu_txpos + 2) & (eup->eu_txsize-1)) << + DMA_COUNT_SHIFT) | DMA_JK; + dma[1] = 0; + + /* + * JK for AAL5 trailer. Set END bit as well. + */ + if ( aal5 ) { + dma[j++] = (((int)(eup->eu_txpos+size) & (eup->eu_txsize-1)) << + DMA_COUNT_SHIFT) | DMA_END_BIT | DMA_JK; + dma[j++] = 0; + } else { + dma[j-2] |= DMA_END_BIT; /* Backup and set END bit */ + } + + /* + * Find out where in adapter memory this TX buffer starts. + */ + tx_send = (Eni_mem) + ((((int)eup->eu_midway[MIDWAY_TXPLACE] & 0x7ff) << ENI_LOC_PREDIV) + + (int)eup->eu_ram); + + /* + * Set descriptor word + */ + tx_send[eup->eu_txpos] = + (MIDWAY_UNQ_ID << 28) | (aal5 ? 1 << 27 : 0) + | (size / WORDS_PER_CELL); + /* + * Set cell header + */ + tx_send[(eup->eu_txpos+1)&(eup->eu_txsize-1)] = + evp->ev_connvc->cvc_vcc->vc_vci << 4; + + /* + * We've got all our resources, count the stats + */ + if ( aal5 ) { + /* + * If this is an AAL5 PDU, we need to set the length + */ + tx_send[(eup->eu_txpos+size-2) & + (eup->eu_txsize-1)] = pdulen; + /* + * Increment AAL5 stats + */ + eup->eu_stats.eni_st_aal5.aal5_pdu_xmit++; + eup->eu_stats.eni_st_aal5.aal5_xmit += (size - 2) / WORDS_PER_CELL; + } else { + /* + * Increment AAL0 stats + */ + eup->eu_stats.eni_st_aal0.aal0_xmit += (size - 2) / WORDS_PER_CELL; + } + /* + * Increment ATM stats + */ + eup->eu_stats.eni_st_atm.atm_xmit += (size - 2) / WORDS_PER_CELL; + + /* + * Store the DMA list + */ + j = j >> 1; + for ( i = 0; i < j; i++ ) { + eup->eu_txdma[dma_wr*2] = dma[i*2]; + eup->eu_txdma[dma_wr*2+1] = dma[i*2+1]; + dma_wr = (dma_wr+1) & (DMA_LIST_SIZE-1); + } + + /* + * Build drain buffer + * + * We toss four words in to help keep track of this + * PDU. The first is a pointer to the VC control block + * so we can find which VCI this went out on, the second + * is the start and stop pointers for the DMA list which + * describes this PDU, the third is the PDU length + * since we'll want to know that for stats gathering, + * and the fourth is the number of DMA words. + */ + KB_DATASTART ( m, up, u_long * ); + *up++ = (u_long)cvp; + *up++ = dma_start << 16 | dma_wr; + *up++ = pdulen; + *up = size; + + /* + * Set length of our buffer + */ + KB_LEN ( m ) = 4 * sizeof ( long ); + + /* + * Place buffers onto transmit queue for draining + */ + s2 = splimp(); + IF_ENQUEUE ( &eup->eu_txqueue, m ); + (void) splx(s2); + + /* + * Update next word to be stored + */ + eup->eu_txpos = ((eup->eu_txpos + size) & (eup->eu_txsize - 1)); + + /* + * Update MIDWAY_TX_WR pointer + */ + eup->eu_midway[MIDWAY_TX_WR] = dma_wr; + + (void) splx ( s ); + + return; +} + diff --git a/sys/dev/hea/eni_var.h b/sys/dev/hea/eni_var.h new file mode 100644 index 0000000..cc83a12 --- /dev/null +++ b/sys/dev/hea/eni_var.h @@ -0,0 +1,85 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: eni_var.h,v 1.4 1998/06/29 19:55:26 jpt Exp $ + * + */ + +/* + * Efficient ENI Adapter Support + * ----------------------------- + * + * Local driver include files and global declarations + * + */ + +#ifndef _ENI_ENI_VAR_H +#define _ENI_ENI_VAR_H + +/* + * Global function declarations + */ + /* eni_buffer.c */ +int eni_init_memory __P((Eni_unit *)); +caddr_t eni_allocate_buffer __P((Eni_unit *, u_long *)); +void eni_free_buffer __P((Eni_unit *, caddr_t)); + + /* eni_if.c */ +int eni_atm_ioctl __P((int, caddr_t, caddr_t)); +void eni_zero_stats __P((Eni_unit *)); + + /* eni_init.c */ +int eni_init __P((Eni_unit *)); + + /* eni_intr.c */ +#if defined(BSD) && BSD < 199506 +int eni_intr __P((void *)); +#else +void eni_intr __P((void *)); +#endif + + /* eni_receive.c */ +void eni_do_service __P((Eni_unit *)); +void eni_recv_drain __P((Eni_unit *)); + + /* eni_transmit.c */ +int eni_set_dma __P((Eni_unit *, int, u_long *, int, long *, int, u_long, int )); +void eni_output __P((Cmn_unit *, Cmn_vcc *, KBuffer *)); +void eni_xmit_drain __P((Eni_unit *)); + + /* eni_vcm.c */ +int eni_instvcc __P((Cmn_unit *, Cmn_vcc *)); +int eni_openvcc __P((Cmn_unit *, Cmn_vcc *)); +int eni_closevcc __P((Cmn_unit *, Cmn_vcc *)); + +/* + * Global variable declarations + */ +extern Eni_unit *eni_units[]; +extern struct stack_defn *eni_services; +extern struct sp_info eni_nif_pool; +extern struct sp_info eni_vcc_pool; + +#endif /* _ENI_ENI_VAR_H */ diff --git a/sys/dev/hea/eni_vcm.c b/sys/dev/hea/eni_vcm.c new file mode 100644 index 0000000..36c2a3d --- /dev/null +++ b/sys/dev/hea/eni_vcm.c @@ -0,0 +1,283 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: eni_vcm.c,v 1.8 1998/06/29 23:03:18 mks Exp $ + * + */ + +/* + * Efficient ENI Adapter Support + * ----------------------------- + * + * Virtual Channel Managment + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: eni_vcm.c,v 1.8 1998/06/29 23:03:18 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <dev/hea/eni_stats.h> +#include <dev/hea/eni.h> +#include <dev/hea/eni_var.h> + + +/* + * VCC Stack Instantiation + * + * This function is called via the common driver code during a device VCC + * stack instantiation. The common code has already validated some of + * the request so we just need to check a few more ENI-specific details. + * + * Called at splnet. + * + * Arguments: + * cup pointer to device common unit + * cvp pointer to common VCC entry + * + * Returns: + * 0 instantiation successful + * err instantiation failed - reason indicated + * + */ +int +eni_instvcc(cup, cvp) + Cmn_unit *cup; + Cmn_vcc *cvp; +{ + Eni_unit *eup = (Eni_unit *)cup; + Eni_vcc *evp = (Eni_vcc *)cvp; + Atm_attributes *ap = &evp->ev_connvc->cvc_attr; + + /* + * Validate requested AAL + */ + switch (ap->aal.type) { + + case ATM_AAL0: + break; + + case ATM_AAL5: + if ((ap->aal.v.aal5.forward_max_SDU_size > ENI_IFF_MTU) || + (ap->aal.v.aal5.backward_max_SDU_size > ENI_IFF_MTU)) { + eup->eu_stats.eni_st_drv.drv_vc_maxpdu++; + return (EINVAL); + } + break; + + default: + return (EINVAL); + } + + return (0); +} + + +/* + * Open a VCC + * + * This function is called via the common driver code after receiving a + * stack *_INIT* command. The common code has already validated most of + * the request so we just need to check a few more ENI-specific details. + * + * Called at splimp. + * + * Arguments: + * cup pointer to device common unit + * cvp pointer to common VCC entry + * + * Returns: + * 0 open sucessful + * err open failed + * + */ +int +eni_openvcc ( cup, cvp ) + Cmn_unit *cup; + Cmn_vcc *cvp; +{ + Eni_unit *eup = (Eni_unit *)cup; + Eni_vcc *evp = (Eni_vcc *)cvp; + struct vccb *vcp = evp->ev_connvc->cvc_vcc; + int err = 0; + + VCI_Table *vct; + int size; + int mode; + int nsize; + + /* + * Validate the VPI and VCI values + */ + if ( (vcp->vc_vpi > eup->eu_pif.pif_maxvpi) || + (vcp->vc_vci > eup->eu_pif.pif_maxvci) ) { + eup->eu_stats.eni_st_drv.drv_vc_badrng++; + return ( EFAULT ); + } + + /* + * Check if this VCI is already active + */ + vct = &eup->eu_vcitbl[ vcp->vc_vci ]; + if ( vct->vci_control >> VCI_MODE_SHIFT != VCI_MODE_TRASH ) { + return ( EEXIST ); + } + + /* + * Allocate some permanent adapter memory for the reassembly + * buffer. Special case the signalling channel(s) buffer size. + * Otherwise, the buffer size will be based on whether this is + * a server or client card. + */ + if ( vcp->vc_vci == UNI_SIG_VCI ) /* HACK */ + size = RX_SIG_BSIZE; + else + size = (eup->eu_ramsize > MAX_CLIENT_RAM * ENI_BUF_PGSZ) ? + RX_SERVER_BSIZE * ENI_BUF_PGSZ : + RX_CLIENT_BSIZE * ENI_BUF_PGSZ; + + if ( ( evp->ev_rxbuf = eni_allocate_buffer ( eup, (u_long *)&size ) ) + == (caddr_t)NULL ) { + return ( ENOMEM ); + } + evp->ev_rxpos = 0; + + /* + * We only need to open incoming VCI's so outbound VCI's + * just get set to CVS_ACTIVE state. + */ + if ( ( vcp->vc_type & VCC_IN ) == 0 ) { + /* + * Set the state and return - nothing else needs to be done. + */ + evp->ev_state = CVS_ACTIVE; + return ( 0 ); + } + + /* + * Set the VCI Table entry to start receiving + */ + mode = ( evp->ev_connvc->cvc_attr.aal.type == ATM_AAL5 + ? VCI_MODE_AAL5 : VCI_MODE_AAL0 ); + size >>= ENI_LOC_PREDIV; /* Predivide by 256 WORDS */ + for ( nsize = -1; size; nsize++ ) + size >>= 1; + + vct->vci_control = mode << VCI_MODE_SHIFT | + PTI_MODE_TRASH << VCI_PTI_SHIFT | + ( (u_int)(evp->ev_rxbuf) >> ENI_LOC_PREDIV ) << VCI_LOC_SHIFT | + nsize << VCI_SIZE_SHIFT; + vct->vci_descr = 0; /* Descr = Rdptr = 0 */ + vct->vci_write = 0; /* WritePtr = CellCount = 0 */ + + /* + * Indicate VC active + */ + evp->ev_state = CVS_ACTIVE; + + return ( err ); +} + +/* + * Close a VCC + * + * This function is called via the common driver code after receiving a + * stack *_TERM* command. The common code has already validated most of + * the request so we just need to check a few more ENI-specific details. + * + * Called at splimp. + * + * Arguments: + * cup pointer to device common unit + * cvp pointer to common VCC entry + * + * Returns: + * 0 close sucessful + * err close failed + * + */ +int +eni_closevcc ( cup, cvp ) + Cmn_unit *cup; + Cmn_vcc *cvp; +{ + Eni_unit *eup = (Eni_unit *)cup; + Eni_vcc *evp = (Eni_vcc *)cvp; + struct vccb *vcp = evp->ev_connvc->cvc_vcc; + int err = 0; + + VCI_Table *vct; + + /* + * Clear any references to this VCC in our transmit queue + */ + /* + * We'll simply allow any existing TX requests to be + * sent as that's easier then pulling them out of + * everywhere. Besides, they should be ignored at the + * receiver whenever the other end shuts down. + */ + + /* + * Free the adapter receive buffer + */ + (void) eni_free_buffer ( eup, (caddr_t)evp->ev_rxbuf ); + + /* + * If this is an outbound only VCI, then we can close + * immediately. + */ + if ( ( vcp->vc_type & VCC_IN ) == 0 ) { + /* + * The state will be set to TERM when we return + * to the *_TERM caller. + */ + return ( 0 ); + } + + /* + * Find VCI entry in VCI Table + */ + vct = &eup->eu_vcitbl[ vcp->vc_vci ]; + + /* + * Reset the VCI state + */ + vct->vci_control = ( vct->vci_control & VCI_MODE_MASK ) + /* | VCI_MODE_TRASH */; + DELAY ( MIDWAY_DELAY ); /* Give the adapter time to */ + /* make the transition */ + + /* + * Reset everything + */ + KM_ZERO ( (caddr_t)vct, sizeof(VCI_Table) ); + + return ( err ); +} + diff --git a/sys/dev/hfa/fore.h b/sys/dev/hfa/fore.h new file mode 100644 index 0000000..42f44f0 --- /dev/null +++ b/sys/dev/hfa/fore.h @@ -0,0 +1,144 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore.h,v 1.8 1998/08/26 23:28:57 mks Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * Protocol and implementation definitions + * + */ + +#ifndef _FORE_H +#define _FORE_H + +#ifndef FORE_DEV_NAME +#define FORE_DEV_NAME "hfa" +#endif + +#define FORE_MAX_UNITS 8 /* Maximum number of devices we support */ +#define FORE_MIN_UCODE 0x20300 /* Minimum microcode version we support */ + +#define FORE_IFF_MTU 9188 /* Network interface MTU */ +#define FORE_MAX_VCC 1024 /* Maximum number of open VCCs */ +#define FORE_MAX_VPI 0 /* Maximum VPI value */ +#define FORE_MAX_VCI 1023 /* Maximum VCI value */ +#define FORE_DEF_RATE 0x00000000 /* Default rate control = disabled */ + +#define XMIT_QUELEN 32 /* Length of transmit queue */ +#define RECV_QUELEN 32 /* Length of receive queue */ +#define CMD_QUELEN 8 /* Length of command queue */ + +#define FORE_TIME_TICK 5 /* Watchdog timer tick (seconds) */ +#define FORE_WATCHDOG 3 /* Device watchdog timeout (ticks) */ +#define FORE_RECV_RETRY 3 /* Wait for receive queue entry retry count */ +#define FORE_RECV_DELAY 10 /* Wait for receive queue entry delay (usec) */ + + +/* + * Receive Buffer strategies + */ +#define BUF_MIN_VCC 4 /* Minimum for buffer supply calculations */ + +#ifdef FORE_SBUS +#if defined(sun4c) +#define BUF_DATA_ALIGN 32 /* Fore-required data alignment */ +#elif defined(sun4m) +#define BUF_DATA_ALIGN 64 /* Fore-required data alignment */ +#endif +#endif +#ifdef FORE_PCI +#define BUF_DATA_ALIGN 4 /* Fore-required data alignment */ +#endif + +#if defined(BSD) +/* + * Strategy 1 Small - mbuf + * Strategy 1 Large - cluster mbuf + * + * XXX buffer controls - the RECV_MAX_SEGS calculation comes out wrong + * using the true buffer size values if the CP really only does full-cell + * filling of a particular buffer - we must clarify this...it also appears + * the minimum buffer size is 64, even if the CP can only fit in 1 cell. + */ +#define SIZEOF_Buf_handle 16 /* XXX sizeof(Buf_handle) */ + +#if BSD >= 199103 +#undef m_ext +typedef struct m_ext M_ext; +#define m_ext M_dat.MH.MH_dat.MH_ext +#define BUF1_SM_HOFF (sizeof(struct m_hdr)) /* Buffer-to-handle offset */ +#define BUF1_SM_HDR (sizeof(struct m_hdr) + sizeof(struct pkthdr)) +#define BUF1_SM_LEN (MHLEN) +#define BUF1_LG_HOFF (sizeof(struct m_hdr) + sizeof(struct pkthdr) \ + + sizeof(M_ext)) /* Buffer-to-handle offset */ +#else +#define BUF1_SM_HOFF (MMINOFF) /* Buffer-to-handle offset */ +#define BUF1_SM_HDR (MMINOFF) +#define BUF1_SM_LEN (MLEN) +#define BUF1_LG_HOFF (MMINOFF + 16) /* Buffer-to-handle offset */ +#endif + +/* + * BUF1_SM_DOFF - CP data offset into buffer data space + * BUF1_SM_SIZE - Buffer size + * + * These should be defined as follows, but we need compile-time constants: + * + * #define BUF1_SM_DOFF (roundup(BUF1_SM_HOFF + SIZEOF_Buf_handle, + * BUF_DATA_ALIGN) - BUF1_SM_HDR) + * #define BUF1_SM_SIZE MAX(BUF1_SM_LEN - BUF1_SM_DOFF, 64) + * + */ +#if ((BSD >= 199103) && defined(FORE_PCI)) +#define BUF1_SM_DOFF ((BUF1_SM_HOFF + SIZEOF_Buf_handle) - BUF1_SM_HDR) +#define BUF1_SM_SIZE (BUF1_SM_LEN - BUF1_SM_DOFF) +#endif +#if ((BSD < 199103) && defined(FORE_SBUS) && defined(sun4c)) +#define BUF1_SM_DOFF (BUF_DATA_ALIGN - BUF1_SM_HDR) +#define BUF1_SM_SIZE (BUF1_SM_LEN - BUF1_SM_DOFF) +#endif +#if ((BSD < 199103) && defined(FORE_SBUS) && defined(sun4m)) +#define BUF1_SM_DOFF (BUF_DATA_ALIGN - BUF1_SM_HDR) +#define BUF1_SM_SIZE (64) +#endif + +#define BUF1_SM_QUELEN 16 /* Entries in supply queue */ +#define BUF1_SM_CPPOOL 256 /* Buffers in CP-resident pool */ +#define BUF1_SM_ENTSIZE 8 /* Buffers in each supply queue entry */ + +#define BUF1_LG_DOFF 0 /* CP data offset into mbuf data space */ +#define BUF1_LG_SIZE MCLBYTES /* Buffer size */ +#define BUF1_LG_QUELEN 16 /* Entries in supply queue */ +#define BUF1_LG_CPPOOL 512 /* Buffers in CP-resident pool */ +#define BUF1_LG_ENTSIZE 8 /* Buffers in each supply queue entry */ + +#endif /* defined(BSD) */ + +#endif /* _FORE_H */ diff --git a/sys/dev/hfa/fore_aali.h b/sys/dev/hfa/fore_aali.h new file mode 100644 index 0000000..d59dcfc --- /dev/null +++ b/sys/dev/hfa/fore_aali.h @@ -0,0 +1,604 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_aali.h,v 1.5 1997/05/09 00:42:25 mks Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * ATM Adaptation Layer Interface (AALI) definitions + * + */ + +#ifndef _FORE_AALI_H +#define _FORE_AALI_H + +/* + * This file contains the definitions required by the FORE ATM Adaptation + * Layer Interface (AALI) specification. + */ + + +/* + * Addressing/Pointer definitions + * + * The CP memory only supports 32-bit word accesses (read and write) - thus, + * all memory must be defined and accessed as 32-bit words. Also, since the + * data transfers are word-sized, we must take care of byte-swapping issues + * from/to little-endian hosts (the CP is an i960 processor, ie big-endian). + * + * All pointers to CP memory areas are actually offsets from the start of + * the adapter RAM address space. + * + * All CP-resident data structures are declared volatile. + */ +typedef void * H_addr; /* Host-resident address */ +typedef unsigned long H_dma; /* Host-resident DMA address */ +typedef unsigned long CP_word; /* CP-resident word */ +typedef unsigned long CP_addr; /* CP-resident CP memory offset */ +typedef unsigned long CP_dma; /* CP-resident DMA address */ + + +/* + * Structure defining the CP's shared memory interface to the mon960 program + */ +struct mon960 { + CP_word mon_xmitmon; /* Uart - host to mon960 (see below) */ + CP_word mon_xmithost; /* Uart - mon960 to host (see below) */ + CP_word mon_bstat; /* Boot status word (see below) */ + CP_addr mon_appl; /* Pointer to application memory area */ + CP_word mon_ver; /* Mon960 firmware version */ +}; +typedef volatile struct mon960 Mon960; + +/* + * Pseudo-UART usage + */ +#define UART_READY 0x00000000 /* UART is ready for more data */ +#define UART_VALID 0x01000000 /* UART character is valid */ +#define UART_DATAMASK 0x000000ff /* UART character data mask */ + +/* + * Boot Status Word + */ +#define BOOT_COLDSTART 0xc01dc01d /* CP is performing cold start */ +#define BOOT_MONREADY 0x02201958 /* Monitor is waiting for commands */ +#define BOOT_FAILTEST 0xadbadbad /* Monitor failed self-test */ +#define BOOT_RUNNING 0xce11feed /* Microcode downloaded and running */ + +#define BOOT_LOOPS 20 /* Loops to wait for CP to boot */ +#define BOOT_DELAY 100000 /* Delay (us) for each boot loop */ + + +/* + * Supported AALs + */ +enum fore_aal { + FORE_AAL_0 = 0, /* Cell Service */ + FORE_AAL_4 = 4, /* AAL 3/4 */ + FORE_AAL_5 = 5 /* AAL 5 */ +}; +typedef enum fore_aal Fore_aal; + + +/* + * Buffer strategy definition + */ +struct buf_strategy { + CP_word bfs_quelen; /* Buffer supply queue entries */ + CP_word bfs_bufsize; /* Buffer size */ + CP_word bfs_cppool; /* Buffers in CP-resident pool */ + CP_word bfs_entsize; /* Buffers in each supply queue entry */ +}; +typedef volatile struct buf_strategy Buf_strategy; + +/* + * Buffer strategy id + */ +#define BUF_STRAT_1 0 /* Buffer strategy one */ +#define BUF_STRAT_2 1 /* Buffer strategy two */ + + + +#ifdef ATM_KERNEL +/* + * Common Queue Element + * + * Used for Transmit, Receive and Buffer Supply Queues + */ +struct com_queue { + CP_dma cq_descr; /* Pointer to element descriptor */ + CP_dma cq_status; /* Pointer to element status word */ +}; +typedef volatile struct com_queue Com_queue; + + +/* + * Queue element status word + */ +typedef volatile unsigned long Q_status; + +#define QSTAT_PENDING 0x01 /* Operation is pending */ +#define QSTAT_COMPLETED 0x02 /* Operation successfully completed */ +#define QSTAT_FREE 0x04 /* Queue element is free/unused */ +#define QSTAT_ERROR 0x08 /* Operation encountered an error */ + +#define QSTAT_ALIGN 4 + + +/* + * PDU Transmit Queue + */ + +/* + * PDU Transmit Queue Element + */ +typedef volatile struct com_queue Xmit_queue; + + +/* + * PDU Transmit buffer segment descriptor + */ +struct xmit_seg_descr { + H_dma xsd_buffer; /* Buffer's DMA address */ + u_int xsd_len; /* Data length in buffer */ +}; +typedef struct xmit_seg_descr Xmit_seg_descr; + +#define XMIT_SEG_ALIGN 4 + + +/* + * PDU Transmit descriptor header + */ +struct xmit_descr_hdr { + u_long xdh_cell_hdr; /* Cell header (minus HEC) */ + u_long xdh_spec; /* Transmit specification (see below) */ + u_long xdh_rate; /* Rate control (data/idle cell ratio)*/ + u_long xdh_pad; /* Pad to quad-word boundary */ +}; +typedef struct xmit_descr_hdr Xmit_descr_hdr; + + +#define XMIT_BLK_BITS 5 /* Bits to encode block size */ +#define XMIT_MAX_BLK_BITS 4 /* Max bits we can use */ +#define XMIT_BLK_SIZE (1 << XMIT_BLK_BITS) +#define XMIT_SEGS_TO_BLKS(nseg) \ + ((((nseg) * sizeof(Xmit_seg_descr)) \ + + sizeof(Xmit_descr_hdr) + (XMIT_BLK_SIZE - 1)) \ + >> XMIT_BLK_BITS) +#define XMIT_MAX_BLKS ((1 << XMIT_MAX_BLK_BITS) - 1) +#define XMIT_HDR_SEGS ((XMIT_BLK_SIZE - sizeof(Xmit_descr_hdr)) \ + / sizeof(Xmit_seg_descr)) +#define XMIT_BLK_SEGS (XMIT_BLK_SIZE / sizeof(Xmit_seg_descr)) +#define XMIT_EXTRA_SEGS ((XMIT_MAX_BLKS - 1) * XMIT_BLK_SEGS) +#define XMIT_MAX_SEGS (XMIT_EXTRA_SEGS + XMIT_HDR_SEGS) + + +/* + * PDU Transmit descriptor + */ +struct xmit_descr { + Xmit_descr_hdr xd_hdr; /* Descriptor header */ + Xmit_seg_descr xd_seg[XMIT_MAX_SEGS]; /* PDU segments */ +}; +typedef struct xmit_descr Xmit_descr; + +#define xd_cell_hdr xd_hdr.xdh_cell_hdr +#define xd_spec xd_hdr.xdh_spec +#define xd_rate xd_hdr.xdh_rate + +/* + * Transmit specification + * + * Bits 0-15 - Total PDU length + * Bits 16-23 - Number of transmit segments + * Bits 24-27 - AAL type + * Bits 28-31 - Interrupt flag + */ +#define XDS_SET_SPEC(i,a,n,l) (((i) << 28) | ((a) << 24) | ((n) << 16) | (l)) +#define XDS_GET_LEN(s) ((s) & 0xffff) +#define XDS_GET_SEGS(s) (((s) >> 16) & 0xff) +#define XDS_GET_AAL(s) (((s) >> 24) & 0xf) +#define XDS_GET_INTR(s) (((s) >> 28) & 0xf) + +#define XMIT_MAX_PDULEN 65535 +#define XMIT_DESCR_ALIGN 32 + + + +/* + * PDU Receive Queue + */ + +/* + * PDU Receive Queue Element + */ +typedef volatile struct com_queue Recv_queue; + + +/* + * Receive PDU buffer segment description + */ +struct recv_seg_descr { + H_addr rsd_handle; /* Buffer handle (from supply) */ + u_int rsd_len; /* Data length in buffer */ +}; +typedef struct recv_seg_descr Recv_seg_descr; + + +/* + * PDU Receive descriptor header + */ +struct recv_descr_hdr { + u_long rdh_cell_hdr; /* Cell header (minus HEC) */ + u_long rdh_nsegs; /* Number of receive segments */ +}; +typedef struct recv_descr_hdr Recv_descr_hdr; + + +#define RECV_BLK_SIZE 32 +#define RECV_HDR_SEGS ((RECV_BLK_SIZE - sizeof(Recv_descr_hdr)) \ + / sizeof(Recv_seg_descr)) +#define RECV_BLK_SEGS (RECV_BLK_SIZE / sizeof(Recv_seg_descr)) +#define RECV_MAX_LG_SEGS ((FORE_IFF_MTU - BUF1_SM_SIZE \ + + (BUF1_LG_SIZE - 1)) / BUF1_LG_SIZE) +#define RECV_EXTRA_BLKS (((RECV_MAX_LG_SEGS + 1 - RECV_HDR_SEGS) \ + + (RECV_BLK_SEGS - 1)) / RECV_BLK_SEGS) +#define RECV_EXTRA_SEGS (RECV_EXTRA_BLKS * RECV_BLK_SEGS) +#define RECV_MAX_SEGS (RECV_EXTRA_SEGS + RECV_HDR_SEGS) + + +/* + * PDU Receive descriptor + */ +struct recv_descr { + Recv_descr_hdr rd_hdr; /* Descriptor header */ + Recv_seg_descr rd_seg[RECV_MAX_SEGS]; /* PDU segments */ +}; +typedef struct recv_descr Recv_descr; + +#define rd_cell_hdr rd_hdr.rdh_cell_hdr +#define rd_nsegs rd_hdr.rdh_nsegs + +#define RECV_DESCR_ALIGN 32 + + + +/* + * Buffer Supply Queue + */ + +/* + * Buffer Supply Queue Element + */ +typedef volatile struct com_queue Buf_queue; + + +/* + * Buffer supply descriptor for supplying receive buffers + */ +struct buf_descr { + H_addr bsd_handle; /* Host-specific buffer handle */ + H_dma bsd_buffer; /* Buffer DMA address */ +}; +typedef struct buf_descr Buf_descr; + +#define BUF_DESCR_ALIGN 32 + + + +/* + * Command Queue + */ + +/* + * Command Codes + */ +typedef volatile unsigned long Cmd_code; + +#define CMD_INIT 0x01 /* Initialize microcode */ +#define CMD_ACT_VCCIN 0x02 /* Activate incoming VCC */ +#define CMD_ACT_VCCOUT 0x03 /* Activate outgoing VCC */ +#define CMD_DACT_VCCIN 0x04 /* Deactivate incoming VCC */ +#define CMD_DACT_VCCOUT 0x05 /* Deactivate outgoing VCC */ +#define CMD_GET_STATS 0x06 /* Get adapter statistics */ +#define CMD_SET_OC3_REG 0x07 /* Set SUNI OC3 registers */ +#define CMD_GET_OC3_REG 0x08 /* Get SUNI OC3 registers */ +#define CMD_GET_PROM 0x09 /* Get PROM data */ +#define CMD_INTR_REQ 0x80 /* Request host interrupt */ + +#endif /* ATM_KERNEL */ + + +/* + * Structure defining the parameters for the Initialize command + */ +struct init_parms { + CP_word init_cmd; /* Command code */ + CP_word init_status; /* Completion status */ + CP_word init_indisc; /* Not used */ + CP_word init_numvcc; /* Number of VCC's supported */ + CP_word init_cmd_elem; /* # of command queue elements */ + CP_word init_xmit_elem; /* # of transmit queue elements */ + CP_word init_recv_elem; /* # of receive queue elements */ + CP_word init_recv_ext; /* # of extra receive descr SEGMENTS */ + CP_word init_xmit_ext; /* # of extra transmit descr SEGMENTS */ + CP_word init_cls_vcc; /* Not used */ + CP_word init_pad[2]; /* Pad to quad-word boundary */ + Buf_strategy init_buf1s; /* Buffer strategy - 1 small */ + Buf_strategy init_buf1l; /* Buffer strategy - 1 large */ + Buf_strategy init_buf2s; /* Buffer strategy - 2 small */ + Buf_strategy init_buf2l; /* Buffer strategy - 2 large */ +}; +typedef volatile struct init_parms Init_parms; + + +#ifdef ATM_KERNEL +/* + * Structure defining the parameters for the Activate commands + */ +struct activate_parms { + CP_word act_spec; /* Command specification (see below) */ + CP_word act_vccid; /* VCC id (VPI=0,VCI=id) */ + CP_word act_batch; /* # cells in batch (AAL=NULL) */ + CP_word act_pad; /* Pad to quad-word boundary */ +}; +typedef volatile struct activate_parms Activate_parms; + +/* + * Activate command specification + * + * Bits 0-7 - command code + * Bits 8-15 - AAL type + * Bits 16-23 - buffer strategy + * Bits 24-31 - reserved + */ +#define ACT_SET_SPEC(b,a,c) (((b) << 16) | ((a) << 8) | (c)) +#define ACT_GET_CMD(s) ((s) & 0xff) +#define ACT_GET_AAL(s) (((s) >> 8) & 0xff) +#define ACT_GET_STRAT(s) (((s) >> 16) & 0xff) + + +/* + * Structure defining the parameters for the Deactivate commands + */ +struct dactivate_parms { + CP_word dact_cmd; /* Command code */ + CP_word dact_vccid; /* VCC id (VPI=0,VCI=id) */ + CP_word dact_pad[2]; /* Pad to quad-word boundary */ +}; +typedef volatile struct dactivate_parms Dactivate_parms; + + +/* + * Structure defining the parameters for the Get Statistics command + */ +struct stats_parms { + CP_word stats_cmd; /* Command code */ + CP_dma stats_buffer; /* DMA address of host stats buffer */ + CP_word stats_pad[2]; /* Pad to quad-word boundary */ +}; +typedef volatile struct stats_parms Stats_parms; + + +/* + * Structure defining the parameters for the SUNI OC3 commands + */ +struct suni_parms { + CP_word suni_spec; /* Command specification (see below) */ + CP_dma suni_buffer; /* DMA address of host SUNI buffer */ + CP_word suni_pad[2]; /* Pad to quad-word boundary */ +}; +typedef volatile struct suni_parms Suni_parms; + +/* + * SUNI OC3 command specification + * + * Bits 0-7 - command code + * Bits 8-15 - SUNI register number + * Bits 16-23 - Value(s) to set in register + * Bits 24-31 - Mask selecting value bits + */ +#define SUNI_SET_SPEC(m,v,r,c) (((m) << 24) | ((v) << 16) | ((r) << 8) | (c)) +#define SUNI_GET_CMD(s) ((s) & 0xff) +#define SUNI_GET_REG(s) (((s) >> 8) & 0xff) +#define SUNI_GET_VALUE(s) (((s) >> 16) & 0xff) +#define SUNI_GET_MASK(s) (((s) >> 24) & 0xff) + + +/* + * Structure defining the parameters for the Get Prom command + */ +struct prom_parms { + CP_word prom_cmd; /* Command code */ + CP_dma prom_buffer; /* DMA address of host prom buffer */ + CP_word prom_pad[2]; /* Pad to quad-word boundary */ +}; +typedef volatile struct prom_parms Prom_parms; + + +/* + * Command Queue Element + */ +struct cmd_queue { + union { /* Command-specific parameters */ + Activate_parms cmdqu_act; + Dactivate_parms cmdqu_dact; + Stats_parms cmdqu_stats; + Suni_parms cmdqu_suni; + Prom_parms cmdqu_prom; + } cmdq_u; + CP_dma cmdq_status; /* Pointer to element status word */ + CP_word cmdq_pad[3]; /* Pad to quad-word boundary */ +}; +#define cmdq_act cmdq_u.cmdqu_act +#define cmdq_dact cmdq_u.cmdqu_dact +#define cmdq_stats cmdq_u.cmdqu_stats +#define cmdq_suni cmdq_u.cmdqu_suni +#define cmdq_prom cmdq_u.cmdqu_prom +typedef volatile struct cmd_queue Cmd_queue; + +#endif /* ATM_KERNEL */ + + + +/* + * Structure defining the CP's shared memory interface to the + * AALI firmware program (downloaded microcode) + */ +struct aali { + CP_addr aali_cmd_q; /* Pointer to command queue */ + CP_addr aali_xmit_q; /* Pointer to transmit queue */ + CP_addr aali_recv_q; /* Pointer to receive queue */ + CP_addr aali_buf1s_q; /* Pointer to strategy-1 small queue */ + CP_addr aali_buf1l_q; /* Pointer to strategy-1 large queue */ + CP_addr aali_buf2s_q; /* Pointer to strategy-2 small queue */ + CP_addr aali_buf2l_q; /* Pointer to strategy-2 large queue */ + CP_word aali_intr_ena; /* Enables interrupts if non-zero */ + CP_word aali_intr_sent; /* Interrupt issued if non-zero */ + CP_addr aali_heap; /* Pointer to application heap */ + CP_word aali_heaplen; /* Length of application heap */ + CP_word aali_hostlog; /* FORE internal use */ + CP_word aali_heartbeat; /* Monitor microcode health */ + CP_word aali_ucode_ver; /* Microcode firmware version */ + CP_word aali_mon_ver; /* Mon960 version */ + CP_word aali_xmit_tput; /* FORE internal use */ + + /* This must be on a quad-word boundary */ + Init_parms aali_init; /* Initialize command parameters */ +}; +typedef volatile struct aali Aali; + + +/* + * CP maintained statistics - DMA'd to host with CMD_GET_STATS command + */ +struct stats_taxi { + u_long taxi_bad_crc; /* Bad header CRC errors */ + u_long taxi_framing; /* Framing errors */ + u_long taxi_pad[2]; /* Pad to quad-word boundary */ +}; +typedef struct stats_taxi Stats_taxi; + +struct stats_oc3 { + u_long oc3_sect_bip8; /* Section 8-bit intrlv parity errors */ + u_long oc3_path_bip8; /* Path 8-bit intrlv parity errors */ + u_long oc3_line_bip24; /* Line 24-bit intrlv parity errors */ + u_long oc3_line_febe; /* Line far-end block errors */ + u_long oc3_path_febe; /* Path far-end block errors */ + u_long oc3_hec_corr; /* Correctible HEC errors */ + u_long oc3_hec_uncorr; /* Uncorrectible HEC errors */ + u_long oc3_pad; /* Pad to quad-word boundary */ +}; +typedef struct stats_oc3 Stats_oc3; + +struct stats_atm { + u_long atm_xmit; /* Cells transmitted */ + u_long atm_rcvd; /* Cells received */ + u_long atm_vpi_range; /* Cell drops - VPI out of range */ + u_long atm_vpi_noconn; /* Cell drops - no connect for VPI */ + u_long atm_vci_range; /* Cell drops - VCI out of range */ + u_long atm_vci_noconn; /* Cell drops - no connect for VCI */ + u_long atm_pad[2]; /* Pad to quad-word boundary */ +}; +typedef struct stats_atm Stats_atm; + +struct stats_aal0 { + u_long aal0_xmit; /* Cells transmitted */ + u_long aal0_rcvd; /* Cells received */ + u_long aal0_drops; /* Cell drops */ + u_long aal0_pad; /* Pad to quad-word boundary */ +}; +typedef struct stats_aal0 Stats_aal0; + +struct stats_aal4 { + u_long aal4_xmit; /* Cells transmitted */ + u_long aal4_rcvd; /* Cells received */ + u_long aal4_crc; /* Cells with payload CRC errors */ + u_long aal4_sar_cs; /* Cells with SAR/CS errors */ + u_long aal4_drops; /* Cell drops */ + u_long aal4_pdu_xmit; /* CS PDUs transmitted */ + u_long aal4_pdu_rcvd; /* CS PDUs received */ + u_long aal4_pdu_errs; /* CS layer protocol errors */ + u_long aal4_pdu_drops; /* CS PDUs dropped */ + u_long aal4_pad[3]; /* Pad to quad-word boundary */ +}; +typedef struct stats_aal4 Stats_aal4; + +struct stats_aal5 { + u_long aal5_xmit; /* Cells transmitted */ + u_long aal5_rcvd; /* Cells received */ + u_long aal5_crc_len; /* Cells with CRC/length errors */ + u_long aal5_drops; /* Cell drops */ + u_long aal5_pdu_xmit; /* CS PDUs transmitted */ + u_long aal5_pdu_rcvd; /* CS PDUs received */ + u_long aal5_pdu_crc; /* CS PDUs with CRC errors */ + u_long aal5_pdu_errs; /* CS layer protocol errors */ + u_long aal5_pdu_drops; /* CS PDUs dropped */ + u_long aal5_pad[3]; /* Pad to quad-word boundary */ +}; +typedef struct stats_aal5 Stats_aal5; + +struct stats_misc { + u_long buf1_sm_fail; /* Alloc fail: buffer strat 1 small */ + u_long buf1_lg_fail; /* Alloc fail: buffer strat 1 large */ + u_long buf2_sm_fail; /* Alloc fail: buffer strat 2 small */ + u_long buf2_lg_fail; /* Alloc fail: buffer strat 2 large */ + u_long rcvd_pdu_fail; /* Received PDU allocation failure */ + u_long carrier_status; /* Carrier status */ + u_long misc_pad[2]; /* Pad to quad-word boundary */ +}; +typedef struct stats_misc Stats_misc; + +struct fore_cp_stats { + Stats_taxi st_cp_taxi; /* TAXI layer statistics */ + Stats_oc3 st_cp_oc3; /* OC3 layer statistics */ + Stats_atm st_cp_atm; /* ATM layer statistics */ + Stats_aal0 st_cp_aal0; /* AAL0 layer statistics */ + Stats_aal4 st_cp_aal4; /* AAL3/4 layer statistics */ + Stats_aal5 st_cp_aal5; /* AAL5 layer statistics */ + Stats_misc st_cp_misc; /* Miscellaneous statistics */ +}; +typedef struct fore_cp_stats Fore_cp_stats; + +#define FORE_STATS_ALIGN 32 + +/* + * CP PROM data - DMA'd to host with CMD_GET_PROM command + */ +struct fore_prom { + u_long pr_hwver; /* Hardware version number */ + u_long pr_serno; /* Serial number */ + u_char pr_mac[8]; /* MAC address */ +}; +typedef struct fore_prom Fore_prom; + +#define FORE_PROM_ALIGN 32 + +#endif /* _FORE_AALI_H */ diff --git a/sys/dev/hfa/fore_buffer.c b/sys/dev/hfa/fore_buffer.c new file mode 100644 index 0000000..d8bdce4 --- /dev/null +++ b/sys/dev/hfa/fore_buffer.c @@ -0,0 +1,772 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_buffer.c,v 1.6 1997/05/06 22:09:21 mks Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * Buffer Supply queue management + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: fore_buffer.c,v 1.6 1997/05/06 22:09:21 mks Exp $"; +#endif + +#include <dev/hfa/fore_include.h> + + +/* + * Local functions + */ +static void fore_buf_drain __P((Fore_unit *)); +static void fore_buf_supply_1s __P((Fore_unit *)); +static void fore_buf_supply_1l __P((Fore_unit *)); + + +/* + * Allocate Buffer Supply Queues Data Structures + * + * Here we are allocating memory for both Strategy 1 Small and Large + * structures contiguously. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * 0 allocations successful + * else allocation failed + */ +int +fore_buf_allocate(fup) + Fore_unit *fup; +{ + caddr_t memp; + + /* + * Allocate non-cacheable memory for buffer supply status words + */ + memp = atm_dev_alloc( + sizeof(Q_status) * (BUF1_SM_QUELEN + BUF1_LG_QUELEN), + QSTAT_ALIGN, ATM_DEV_NONCACHE); + if (memp == NULL) { + return (1); + } + fup->fu_buf1s_stat = (Q_status *) memp; + fup->fu_buf1l_stat = ((Q_status *) memp) + BUF1_SM_QUELEN; + + memp = DMA_GET_ADDR(fup->fu_buf1s_stat, + sizeof(Q_status) * (BUF1_SM_QUELEN + BUF1_LG_QUELEN), + QSTAT_ALIGN, ATM_DEV_NONCACHE); + if (memp == NULL) { + return (1); + } + fup->fu_buf1s_statd = (Q_status *) memp; + fup->fu_buf1l_statd = ((Q_status *) memp) + BUF1_SM_QUELEN; + + /* + * Allocate memory for buffer supply descriptors + */ + memp = atm_dev_alloc(sizeof(Buf_descr) * + ((BUF1_SM_QUELEN * BUF1_SM_ENTSIZE) + + (BUF1_LG_QUELEN * BUF1_LG_ENTSIZE)), + BUF_DESCR_ALIGN, 0); + if (memp == NULL) { + return (1); + } + fup->fu_buf1s_desc = (Buf_descr *) memp; + fup->fu_buf1l_desc = ((Buf_descr *) memp) + + (BUF1_SM_QUELEN * BUF1_SM_ENTSIZE); + + memp = DMA_GET_ADDR(fup->fu_buf1s_desc, sizeof(Buf_descr) * + ((BUF1_SM_QUELEN * BUF1_SM_ENTSIZE) + + (BUF1_LG_QUELEN * BUF1_LG_ENTSIZE)), + BUF_DESCR_ALIGN, 0); + if (memp == NULL) { + return (1); + } + fup->fu_buf1s_descd = (Buf_descr *) memp; + fup->fu_buf1l_descd = ((Buf_descr *) memp) + + (BUF1_SM_QUELEN * BUF1_SM_ENTSIZE); + + return (0); +} + + +/* + * Buffer Supply Queues Initialization + * + * Allocate and initialize the host-resident buffer supply queue structures + * and then initialize the CP-resident queue structures. + * + * Called at interrupt level. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +void +fore_buf_initialize(fup) + Fore_unit *fup; +{ + Aali *aap = fup->fu_aali; + Buf_queue *cqp; + H_buf_queue *hbp; + Buf_descr *bdp; + Buf_descr *bdp_dma; + Q_status *qsp; + Q_status *qsp_dma; + int i; + + /* + * Initialize Strategy 1 Small Queues + */ + + /* + * Point to CP-resident buffer supply queue + */ + cqp = (Buf_queue *)(fup->fu_ram + CP_READ(aap->aali_buf1s_q)); + + /* + * Point to host-resident buffer supply queue structures + */ + hbp = fup->fu_buf1s_q; + qsp = fup->fu_buf1s_stat; + qsp_dma = fup->fu_buf1s_statd; + bdp = fup->fu_buf1s_desc; + bdp_dma = fup->fu_buf1s_descd; + + /* + * Loop thru all queue entries and do whatever needs doing + */ + for (i = 0; i < BUF1_SM_QUELEN; i++) { + + /* + * Set queue status word to free + */ + *qsp = QSTAT_FREE; + + /* + * Set up host queue entry and link into ring + */ + hbp->hbq_cpelem = cqp; + hbp->hbq_status = qsp; + hbp->hbq_descr = bdp; + hbp->hbq_descr_dma = bdp_dma; + if (i == (BUF1_SM_QUELEN - 1)) + hbp->hbq_next = fup->fu_buf1s_q; + else + hbp->hbq_next = hbp + 1; + + /* + * Now let the CP into the game + */ + cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma); + + /* + * Bump all queue pointers + */ + hbp++; + qsp++; + qsp_dma++; + bdp += BUF1_SM_ENTSIZE; + bdp_dma += BUF1_SM_ENTSIZE; + cqp++; + } + + /* + * Initialize queue pointers + */ + fup->fu_buf1s_head = fup->fu_buf1s_tail = fup->fu_buf1s_q; + + + /* + * Initialize Strategy 1 Large Queues + */ + + /* + * Point to CP-resident buffer supply queue + */ + cqp = (Buf_queue *)(fup->fu_ram + CP_READ(aap->aali_buf1l_q)); + + /* + * Point to host-resident buffer supply queue structures + */ + hbp = fup->fu_buf1l_q; + qsp = fup->fu_buf1l_stat; + qsp_dma = fup->fu_buf1l_statd; + bdp = fup->fu_buf1l_desc; + bdp_dma = fup->fu_buf1l_descd; + + /* + * Loop thru all queue entries and do whatever needs doing + */ + for (i = 0; i < BUF1_LG_QUELEN; i++) { + + /* + * Set queue status word to free + */ + *qsp = QSTAT_FREE; + + /* + * Set up host queue entry and link into ring + */ + hbp->hbq_cpelem = cqp; + hbp->hbq_status = qsp; + hbp->hbq_descr = bdp; + hbp->hbq_descr_dma = bdp_dma; + if (i == (BUF1_LG_QUELEN - 1)) + hbp->hbq_next = fup->fu_buf1l_q; + else + hbp->hbq_next = hbp + 1; + + /* + * Now let the CP into the game + */ + cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma); + + /* + * Bump all queue pointers + */ + hbp++; + qsp++; + qsp_dma++; + bdp += BUF1_LG_ENTSIZE; + bdp_dma += BUF1_LG_ENTSIZE; + cqp++; + } + + /* + * Initialize queue pointers + */ + fup->fu_buf1l_head = fup->fu_buf1l_tail = fup->fu_buf1l_q; + + return; +} + + +/* + * Supply Buffers to CP + * + * This function will resupply the CP with buffers to be used to + * store incoming data. + * + * May be called in interrupt state. + * Must be called with interrupts locked out. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +void +fore_buf_supply(fup) + Fore_unit *fup; +{ + + /* + * First, clean out the supply queues + */ + fore_buf_drain(fup); + + /* + * Then, supply the buffers for each queue + */ + fore_buf_supply_1s(fup); + fore_buf_supply_1l(fup); + + return; +} + + +/* + * Supply Strategy 1 Small Buffers to CP + * + * May be called in interrupt state. + * Must be called with interrupts locked out. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +static void +fore_buf_supply_1s(fup) + Fore_unit *fup; +{ + H_buf_queue *hbp; + Buf_queue *cqp; + Buf_descr *bdp; + Buf_handle *bhp; + KBuffer *m; + int nvcc, nbuf, i; + + /* + * Figure out how many buffers we should be giving to the CP. + * We're basing this calculation on the current number of open + * VCCs thru this device, with certain minimum and maximum values + * enforced. This will then allow us to figure out how many more + * buffers we need to supply to the CP. This will be rounded up + * to fill a supply queue entry. + */ + nvcc = MAX(fup->fu_open_vcc, BUF_MIN_VCC); + nbuf = nvcc * 4; + nbuf = MIN(nbuf, BUF1_SM_CPPOOL); + nbuf -= fup->fu_buf1s_cnt; + nbuf = roundup(nbuf, BUF1_SM_ENTSIZE); + + /* + * OK, now supply the buffers to the CP + */ + while (nbuf > 0) { + + /* + * Acquire a supply queue entry + */ + hbp = fup->fu_buf1s_tail; + if (!((*hbp->hbq_status) & QSTAT_FREE)) + break; + bdp = hbp->hbq_descr; + + /* + * Get a buffer for each descriptor in the queue entry + */ + for (i = 0; i < BUF1_SM_ENTSIZE; i++, bdp++) { + caddr_t cp; + + /* + * Get a small buffer + */ + KB_ALLOCPKT(m, BUF1_SM_SIZE, KB_F_NOWAIT, KB_T_DATA); + if (m == 0) { + break; + } + KB_HEADSET(m, BUF1_SM_DOFF); + + /* + * Point to buffer handle structure + */ + bhp = (Buf_handle *)((caddr_t)m + BUF1_SM_HOFF); + bhp->bh_type = BHT_S1_SMALL; + + /* + * Setup buffer descriptor + */ + bdp->bsd_handle = bhp; + KB_DATASTART(m, cp, caddr_t); + bhp->bh_dma = bdp->bsd_buffer = (H_dma) DMA_GET_ADDR( + cp, BUF1_SM_SIZE, BUF_DATA_ALIGN, 0); + if (bdp->bsd_buffer == NULL) { + /* + * Unable to assign dma address - free up + * this descriptor's buffer + */ + fup->fu_stats->st_drv.drv_bf_segdma++; + KB_FREEALL(m); + break; + } + + /* + * All set, so queue buffer (handle) + */ + ENQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1s_bq); + } + + /* + * If we we're not able to fill all the descriptors for + * an entry, free up what's been partially built + */ + if (i != BUF1_SM_ENTSIZE) { + + /* + * Clean up each used descriptor + */ + for (bdp = hbp->hbq_descr; i; i--, bdp++) { + + bhp = bdp->bsd_handle; + + DEQUEUE(bhp, Buf_handle, bh_qelem, + fup->fu_buf1s_bq); + + m = (KBuffer *) + ((caddr_t)bhp - BUF1_SM_HOFF); + KB_FREEALL(m); + } + break; + } + + /* + * Finally, we've got an entry ready for the CP. + * So claim the host queue entry and setup the CP-resident + * queue entry. The CP will (potentially) grab the supplied + * buffers when the descriptor pointer is set. + */ + fup->fu_buf1s_tail = hbp->hbq_next; + (*hbp->hbq_status) = QSTAT_PENDING; + cqp = hbp->hbq_cpelem; + cqp->cq_descr = (CP_dma) CP_WRITE((u_long)hbp->hbq_descr_dma); + + /* + * Update counters, etc for supplied buffers + */ + fup->fu_buf1s_cnt += BUF1_SM_ENTSIZE; + nbuf -= BUF1_SM_ENTSIZE; + } + + return; +} + + +/* + * Supply Strategy 1 Large Buffers to CP + * + * May be called in interrupt state. + * Must be called with interrupts locked out. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +static void +fore_buf_supply_1l(fup) + Fore_unit *fup; +{ + H_buf_queue *hbp; + Buf_queue *cqp; + Buf_descr *bdp; + Buf_handle *bhp; + KBuffer *m; + int nvcc, nbuf, i; + + /* + * Figure out how many buffers we should be giving to the CP. + * We're basing this calculation on the current number of open + * VCCs thru this device, with certain minimum and maximum values + * enforced. This will then allow us to figure out how many more + * buffers we need to supply to the CP. This will be rounded up + * to fill a supply queue entry. + */ + nvcc = MAX(fup->fu_open_vcc, BUF_MIN_VCC); + nbuf = nvcc * 4 * RECV_MAX_SEGS; + nbuf = MIN(nbuf, BUF1_LG_CPPOOL); + nbuf -= fup->fu_buf1l_cnt; + nbuf = roundup(nbuf, BUF1_LG_ENTSIZE); + + /* + * OK, now supply the buffers to the CP + */ + while (nbuf > 0) { + + /* + * Acquire a supply queue entry + */ + hbp = fup->fu_buf1l_tail; + if (!((*hbp->hbq_status) & QSTAT_FREE)) + break; + bdp = hbp->hbq_descr; + + /* + * Get a buffer for each descriptor in the queue entry + */ + for (i = 0; i < BUF1_LG_ENTSIZE; i++, bdp++) { + caddr_t cp; + + /* + * Get a cluster buffer + */ + KB_ALLOCEXT(m, BUF1_LG_SIZE, KB_F_NOWAIT, KB_T_DATA); + if (m == 0) { + break; + } + KB_HEADSET(m, BUF1_LG_DOFF); + + /* + * Point to buffer handle structure + */ + bhp = (Buf_handle *)((caddr_t)m + BUF1_LG_HOFF); + bhp->bh_type = BHT_S1_LARGE; + + /* + * Setup buffer descriptor + */ + bdp->bsd_handle = bhp; + KB_DATASTART(m, cp, caddr_t); + bhp->bh_dma = bdp->bsd_buffer = (H_dma) DMA_GET_ADDR( + cp, BUF1_LG_SIZE, BUF_DATA_ALIGN, 0); + if (bdp->bsd_buffer == NULL) { + /* + * Unable to assign dma address - free up + * this descriptor's buffer + */ + fup->fu_stats->st_drv.drv_bf_segdma++; + KB_FREEALL(m); + break; + } + + /* + * All set, so queue buffer (handle) + */ + ENQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1l_bq); + } + + /* + * If we we're not able to fill all the descriptors for + * an entry, free up what's been partially built + */ + if (i != BUF1_LG_ENTSIZE) { + + /* + * Clean up each used descriptor + */ + for (bdp = hbp->hbq_descr; i; i--, bdp++) { + bhp = bdp->bsd_handle; + + DEQUEUE(bhp, Buf_handle, bh_qelem, + fup->fu_buf1l_bq); + + m = (KBuffer *) + ((caddr_t)bhp - BUF1_LG_HOFF); + KB_FREEALL(m); + } + break; + } + + /* + * Finally, we've got an entry ready for the CP. + * So claim the host queue entry and setup the CP-resident + * queue entry. The CP will (potentially) grab the supplied + * buffers when the descriptor pointer is set. + */ + fup->fu_buf1l_tail = hbp->hbq_next; + (*hbp->hbq_status) = QSTAT_PENDING; + cqp = hbp->hbq_cpelem; + cqp->cq_descr = (CP_dma) CP_WRITE((u_long)hbp->hbq_descr_dma); + + /* + * Update counters, etc for supplied buffers + */ + fup->fu_buf1l_cnt += BUF1_LG_ENTSIZE; + nbuf -= BUF1_LG_ENTSIZE; + } + + return; +} + + +/* + * Drain Buffer Supply Queues + * + * This function will free all completed entries at the head of each + * buffer supply queue. Since we consider the CP to "own" the buffers + * once we put them on a supply queue and since a completed supply queue + * entry is only telling us that the CP has accepted the buffers that we + * gave to it, there's not much to do here. + * + * May be called in interrupt state. + * Must be called with interrupts locked out. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +static void +fore_buf_drain(fup) + Fore_unit *fup; +{ + H_buf_queue *hbp; + + /* + * Drain Strategy 1 Small Queue + */ + + /* + * Process each completed entry + */ + while (*fup->fu_buf1s_head->hbq_status & QSTAT_COMPLETED) { + + hbp = fup->fu_buf1s_head; + + if (*hbp->hbq_status & QSTAT_ERROR) { + /* + * XXX - what does this mean??? + */ + log(LOG_ERR, "fore_buf_drain: buf1s queue error\n"); + } + + /* + * Mark this entry free for use and bump head pointer + * to the next entry in the queue + */ + *hbp->hbq_status = QSTAT_FREE; + fup->fu_buf1s_head = hbp->hbq_next; + } + + + /* + * Drain Strategy 1 Large Queue + */ + + /* + * Process each completed entry + */ + while (*fup->fu_buf1l_head->hbq_status & QSTAT_COMPLETED) { + + hbp = fup->fu_buf1l_head; + + if (*hbp->hbq_status & QSTAT_ERROR) { + /* + * XXX - what does this mean??? + */ + log(LOG_ERR, "fore_buf_drain: buf1l queue error\n"); + } + + /* + * Mark this entry free for use and bump head pointer + * to the next entry in the queue + */ + *hbp->hbq_status = QSTAT_FREE; + fup->fu_buf1l_head = hbp->hbq_next; + } + + return; +} + + +/* + * Free Buffer Supply Queue Data Structures + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +void +fore_buf_free(fup) + Fore_unit *fup; +{ + Buf_handle *bhp; + KBuffer *m; + + /* + * Free any previously supplied and not returned buffers + */ + if (fup->fu_flags & CUF_INITED) { + + /* + * Run through Strategy 1 Small queue + */ + while (bhp = Q_HEAD(fup->fu_buf1s_bq, Buf_handle)) { + caddr_t cp; + + /* + * Back off to buffer + */ + m = (KBuffer *)((caddr_t)bhp - BUF1_SM_HOFF); + + /* + * Dequeue handle and free buffer + */ + DEQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1s_bq); + + KB_DATASTART(m, cp, caddr_t); + DMA_FREE_ADDR(cp, bhp->bh_dma, BUF1_SM_SIZE, 0); + + KB_FREEALL(m); + } + + /* + * Run through Strategy 1 Large queue + */ + while (bhp = Q_HEAD(fup->fu_buf1l_bq, Buf_handle)) { + caddr_t cp; + + /* + * Back off to buffer + */ + m = (KBuffer *)((caddr_t)bhp - BUF1_LG_HOFF); + + /* + * Dequeue handle and free buffer + */ + DEQUEUE(bhp, Buf_handle, bh_qelem, fup->fu_buf1l_bq); + + KB_DATASTART(m, cp, caddr_t); + DMA_FREE_ADDR(cp, bhp->bh_dma, BUF1_LG_SIZE, 0); + + KB_FREEALL(m); + } + } + + /* + * Free the status words + */ + if (fup->fu_buf1s_stat) { + if (fup->fu_buf1s_statd) { + DMA_FREE_ADDR(fup->fu_buf1s_stat, fup->fu_buf1s_statd, + sizeof(Q_status) * + (BUF1_SM_QUELEN + BUF1_LG_QUELEN), + ATM_DEV_NONCACHE); + } + atm_dev_free((void *)fup->fu_buf1s_stat); + fup->fu_buf1s_stat = NULL; + fup->fu_buf1s_statd = NULL; + fup->fu_buf1l_stat = NULL; + fup->fu_buf1l_statd = NULL; + } + + /* + * Free the transmit descriptors + */ + if (fup->fu_buf1s_desc) { + if (fup->fu_buf1s_descd) { + DMA_FREE_ADDR(fup->fu_buf1s_desc, fup->fu_buf1s_descd, + sizeof(Buf_descr) * + ((BUF1_SM_QUELEN * BUF1_SM_ENTSIZE) + + (BUF1_LG_QUELEN * BUF1_LG_ENTSIZE)), + 0); + } + atm_dev_free(fup->fu_buf1s_desc); + fup->fu_buf1s_desc = NULL; + fup->fu_buf1s_descd = NULL; + fup->fu_buf1l_desc = NULL; + fup->fu_buf1l_descd = NULL; + } + + return; +} + diff --git a/sys/dev/hfa/fore_command.c b/sys/dev/hfa/fore_command.c new file mode 100644 index 0000000..29b99c6 --- /dev/null +++ b/sys/dev/hfa/fore_command.c @@ -0,0 +1,445 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_command.c,v 1.10 1998/06/29 21:42:09 mks Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * Command queue management + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: fore_command.c,v 1.10 1998/06/29 21:42:09 mks Exp $"; +#endif + +#include <dev/hfa/fore_include.h> + +/* + * Local variables + */ +static struct t_atm_cause fore_cause = { + T_ATM_ITU_CODING, + T_ATM_LOC_USER, + T_ATM_CAUSE_TEMPORARY_FAILURE, + {0, 0, 0, 0} +}; + + +/* + * Allocate Command Queue Data Structures + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * 0 allocations successful + * else allocation failed + */ +int +fore_cmd_allocate(fup) + Fore_unit *fup; +{ + caddr_t memp; + + /* + * Allocate non-cacheable memory for command status words + */ + memp = atm_dev_alloc(sizeof(Q_status) * CMD_QUELEN, + QSTAT_ALIGN, ATM_DEV_NONCACHE); + if (memp == NULL) { + return (1); + } + fup->fu_cmd_stat = (Q_status *) memp; + + memp = DMA_GET_ADDR(fup->fu_cmd_stat, sizeof(Q_status) * CMD_QUELEN, + QSTAT_ALIGN, ATM_DEV_NONCACHE); + if (memp == NULL) { + return (1); + } + fup->fu_cmd_statd = (Q_status *) memp; + + /* + * Allocate memory for statistics buffer + */ + memp = atm_dev_alloc(sizeof(Fore_stats), FORE_STATS_ALIGN, 0); + if (memp == NULL) { + return (1); + } + fup->fu_stats = (Fore_stats *) memp; + +#ifdef FORE_PCI + /* + * Allocate memory for PROM buffer + */ + memp = atm_dev_alloc(sizeof(Fore_prom), FORE_PROM_ALIGN, 0); + if (memp == NULL) { + return (1); + } + fup->fu_prom = (Fore_prom *) memp; +#endif + + return (0); +} + + +/* + * Command Queue Initialization + * + * Allocate and initialize the host-resident command queue structures + * and then initialize the CP-resident queue structures. + * + * Called at interrupt level. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +void +fore_cmd_initialize(fup) + Fore_unit *fup; +{ + Aali *aap = fup->fu_aali; + Cmd_queue *cqp; + H_cmd_queue *hcp; + Q_status *qsp; + Q_status *qsp_dma; + int i; + + /* + * Point to CP-resident command queue + */ + cqp = (Cmd_queue *)(fup->fu_ram + CP_READ(aap->aali_cmd_q)); + + /* + * Point to host-resident command queue structures + */ + hcp = fup->fu_cmd_q; + qsp = fup->fu_cmd_stat; + qsp_dma = fup->fu_cmd_statd; + + /* + * Loop thru all queue entries and do whatever needs doing + */ + for (i = 0; i < CMD_QUELEN; i++) { + + /* + * Set queue status word to free + */ + *qsp = QSTAT_FREE; + + /* + * Set up host queue entry and link into ring + */ + hcp->hcq_cpelem = cqp; + hcp->hcq_status = qsp; + if (i == (CMD_QUELEN - 1)) + hcp->hcq_next = fup->fu_cmd_q; + else + hcp->hcq_next = hcp + 1; + + /* + * Now let the CP into the game + */ + cqp->cmdq_status = (CP_dma) CP_WRITE(qsp_dma); + + /* + * Bump all queue pointers + */ + hcp++; + qsp++; + qsp_dma++; + cqp++; + } + + /* + * Initialize queue pointers + */ + fup->fu_cmd_head = fup->fu_cmd_tail = fup->fu_cmd_q; + + return; +} + + +/* + * Drain Command Queue + * + * This function will process and free all completed entries at the head + * of the command queue. + * + * May be called in interrupt state. + * Must be called with interrupts locked out. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +void +fore_cmd_drain(fup) + Fore_unit *fup; +{ + H_cmd_queue *hcp; + Fore_vcc *fvp; + + /* + * Process each completed entry + */ + while (*fup->fu_cmd_head->hcq_status & QSTAT_COMPLETED) { + + hcp = fup->fu_cmd_head; + + /* + * Process command completion + */ + switch (hcp->hcq_code) { + + case CMD_ACT_VCCIN: + case CMD_ACT_VCCOUT: + fvp = hcp->hcq_arg; + if (*hcp->hcq_status & QSTAT_ERROR) { + /* + * VCC activation failed - just abort vcc + */ + if (fvp) + atm_cm_abort(fvp->fv_connvc, + &fore_cause); + fup->fu_pif.pif_cmderrors++; + } else { + /* + * Successful VCC activation + */ + if (fvp) { + fvp->fv_state = CVS_ACTIVE; + fup->fu_open_vcc++; + } + } + break; + + case CMD_DACT_VCCIN: + case CMD_DACT_VCCOUT: + fvp = hcp->hcq_arg; + if (*hcp->hcq_status & QSTAT_ERROR) { + /* + * VCC dactivation failed - whine + */ + log(LOG_ERR, + "fore_cmd_drain: DACT failed, vcc=(%d,%d)\n", + fvp->fv_connvc->cvc_vcc->vc_vpi, + fvp->fv_connvc->cvc_vcc->vc_vci); + fup->fu_pif.pif_cmderrors++; + } else { + /* + * Successful VCC dactivation - so what? + */ + } + break; + + case CMD_GET_STATS: + if (*hcp->hcq_status & QSTAT_ERROR) { + /* + * Couldn't get stats + */ + fup->fu_pif.pif_cmderrors++; + fup->fu_stats_ret = EIO; + } else { + /* + * Stats are now in unit buffer + */ + fup->fu_stats_ret = 0; + } + DMA_FREE_ADDR(fup->fu_stats, fup->fu_statsd, + sizeof(Fore_cp_stats), 0); + fup->fu_flags &= ~FUF_STATCMD; + + /* + * Flush received stats data + */ +#ifdef VAC + if (vac) + vac_pageflush((addr_t)fup->fu_stats); +#endif + +#if BYTE_ORDER == LITTLE_ENDIAN + /* + * Little endian machines receives the stats in + * wrong byte order. Instead of swapping in user + * land, swap here so that everything going out + * of the kernel is in correct host order. + */ + { + u_long *bp = (u_long *)fup->fu_stats; + int loop; + + for ( loop = 0; loop < sizeof(Fore_cp_stats)/ + sizeof(long); loop++, bp++ ) + *bp = ntohl(*bp); + } +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ + + /* + * Poke whoever is waiting on the stats + */ + wakeup((caddr_t)&fup->fu_stats); + break; + +#ifdef FORE_PCI + case CMD_GET_PROM: + if (*hcp->hcq_status & QSTAT_ERROR) { + /* + * Couldn't get PROM data + */ + fup->fu_pif.pif_cmderrors++; + log(LOG_ERR, + "fore_cmd_drain: %s%d: GET_PROM failed\n", + fup->fu_pif.pif_name, + fup->fu_pif.pif_unit); + } else { + Fore_prom *fp = fup->fu_prom; + + /* + * Flush received PROM data + */ +#ifdef VAC + if (vac) + vac_pageflush((addr_t)fp); +#endif + /* + * Copy PROM info into config areas + */ + KM_COPY(&fp->pr_mac[2], + &fup->fu_pif.pif_macaddr, + sizeof(struct mac_addr)); + fup->fu_config.ac_macaddr = + fup->fu_pif.pif_macaddr; + sprintf(fup->fu_config.ac_hard_vers, "%d.%d.%d", + (fp->pr_hwver >> 16) & 0xff, + (fp->pr_hwver >> 8) & 0xff, + fp->pr_hwver & 0xff); + fup->fu_config.ac_serial = fp->pr_serno; + } + + DMA_FREE_ADDR(fup->fu_prom, fup->fu_promd, + sizeof(Fore_prom), 0); + break; +#endif /* FORE_PCI */ + + default: + log(LOG_ERR, "fore_cmd_drain: unknown command %d\n", + hcp->hcq_code); + } + + /* + * Mark this entry free for use and bump head pointer + * to the next entry in the queue + */ + *hcp->hcq_status = QSTAT_FREE; + fup->fu_cmd_head = hcp->hcq_next; + } + + return; +} + + +/* + * Free Command Queue Data Structures + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +void +fore_cmd_free(fup) + Fore_unit *fup; +{ + H_cmd_queue *hcp; + + /* + * Deal with any commands left on the queue + */ + if (fup->fu_flags & CUF_INITED) { + while (*fup->fu_cmd_head->hcq_status != QSTAT_FREE) { + hcp = fup->fu_cmd_head; + + switch (hcp->hcq_code) { + + case CMD_GET_STATS: + /* + * Just in case someone is sleeping on this + */ + fup->fu_stats_ret = EIO; + wakeup((caddr_t)&fup->fu_stats); + break; + } + + *hcp->hcq_status = QSTAT_FREE; + fup->fu_cmd_head = hcp->hcq_next; + } + } + + /* + * Free the statistics buffer + */ + if (fup->fu_stats) { + atm_dev_free(fup->fu_stats); + fup->fu_stats = NULL; + } + +#ifdef FORE_PCI + /* + * Free the PROM buffer + */ + if (fup->fu_prom) { + atm_dev_free(fup->fu_prom); + fup->fu_prom = NULL; + } +#endif + + /* + * Free the status words + */ + if (fup->fu_cmd_stat) { + if (fup->fu_cmd_statd) { + DMA_FREE_ADDR(fup->fu_cmd_stat, fup->fu_cmd_statd, + sizeof(Q_status) * CMD_QUELEN, + ATM_DEV_NONCACHE); + } + atm_dev_free((void *)fup->fu_cmd_stat); + fup->fu_cmd_stat = NULL; + fup->fu_cmd_statd = NULL; + } + + return; +} + diff --git a/sys/dev/hfa/fore_globals.c b/sys/dev/hfa/fore_globals.c new file mode 100644 index 0000000..4abc5fa --- /dev/null +++ b/sys/dev/hfa/fore_globals.c @@ -0,0 +1,119 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_globals.c,v 1.6 1997/05/06 22:09:31 mks Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * Global variable definitions + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: fore_globals.c,v 1.6 1997/05/06 22:09:31 mks Exp $"; +#endif + +#include <dev/hfa/fore_include.h> + + +/* + * Supported device models + */ +Fore_device fore_devices[] = { +#ifdef FORE_SBUS + {SBA200E_PROM_NAME, DEV_FORE_SBA200E}, + {SBA200_PROM_NAME, DEV_FORE_SBA200}, +#endif + {""} +}; + + +/* + * Device unit table + */ +Fore_unit *fore_units[FORE_MAX_UNITS] = {NULL}; +int fore_nunits = 0; + + +/* + * ATM Interface services + */ +static struct stack_defn fore_svaal5 = { + NULL, + SAP_CPCS_AAL5, + SDF_TERM, + atm_dev_inst, + atm_dev_lower, + NULL, + 0, +}; +static struct stack_defn fore_svaal4 = { + &fore_svaal5, + SAP_CPCS_AAL3_4, + SDF_TERM, + atm_dev_inst, + atm_dev_lower, + NULL, + 0, +}; +static struct stack_defn fore_svaal0 = { + &fore_svaal4, + SAP_ATM, + SDF_TERM, + atm_dev_inst, + atm_dev_lower, + NULL, + 0, +}; +struct stack_defn *fore_services = &fore_svaal0; + + +/* + * Storage pools + */ +struct sp_info fore_nif_pool = { + "fore nif pool", /* si_name */ + sizeof(struct atm_nif), /* si_blksiz */ + 5, /* si_blkcnt */ + 20 /* si_maxallow */ +}; + +struct sp_info fore_vcc_pool = { + "fore vcc pool", /* si_name */ + sizeof(Fore_vcc), /* si_blksiz */ + 10, /* si_blkcnt */ + 100 /* si_maxallow */ +}; + + +/* + * Watchdog timer + */ +struct atm_time fore_timer = {0, 0}; + diff --git a/sys/dev/hfa/fore_if.c b/sys/dev/hfa/fore_if.c new file mode 100644 index 0000000..7d3b3b6 --- /dev/null +++ b/sys/dev/hfa/fore_if.c @@ -0,0 +1,205 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_if.c,v 1.6 1998/08/26 23:28:58 mks Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * Network interface layer support + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: fore_if.c,v 1.6 1998/08/26 23:28:58 mks Exp $"; +#endif + +#include <dev/hfa/fore_include.h> + + +/* + * Handle netatm core service interface ioctl requests + * + * Called at splnet. + * + * Arguments: + * code ioctl function (sub)code + * data data to/from ioctl + * arg optional code-specific argument + * + * Returns: + * 0 request processed successfully + * error request failed - reason code + */ +int +fore_atm_ioctl(code, data, arg) + int code; + caddr_t data; + caddr_t arg; +{ + struct atminfreq *aip = (struct atminfreq *)data; + struct atm_pif *pip; + Fore_unit *fup; + caddr_t buf = aip->air_buf_addr; + struct air_vinfo_rsp *avr; + int count, len, buf_len = aip->air_buf_len; + int err = 0; + char ifname[2*IFNAMSIZ]; + + + ATM_DEBUG2("fore_atm_ioctl: code=%d, opcode=%d\n", + code, aip->air_opcode); + + switch ( aip->air_opcode ) { + + case AIOCS_INF_VST: + /* + * Get vendor statistics + */ + pip = (struct atm_pif *)arg; + fup = (Fore_unit *)pip; + if ( pip == NULL ) + return ( ENXIO ); + sprintf ( ifname, "%s%d", pip->pif_name, pip->pif_unit ); + + /* + * Cast response structure onto user's buffer + */ + avr = (struct air_vinfo_rsp *)buf; + + /* + * How large is the response structure? + */ + len = sizeof(struct air_vinfo_rsp); + + /* + * Sanity check - enough room for response structure? + */ + if ( buf_len < len ) + return ( ENOSPC ); + + /* + * Copy interface name into response structure + */ + if ( err = copyout ( ifname, avr->avsp_intf, IFNAMSIZ ) ) + break; + + /* + * Advance the buffer address and decrement the size + */ + buf += len; + buf_len -= len; + + /* + * Get the vendor stats from the hardware + */ + count = 0; + if ( ( err = fore_get_stats ( fup ) ) == 0 ) + { + /* + * Stick as much of it as we have room for + * into the response + */ + count = min ( sizeof(Fore_stats), buf_len ); + + /* + * Copy stats into user's buffer. Return value is + * amount of data copied. + */ + if (err = copyout((caddr_t)fup->fu_stats, buf, count)) + break; + buf += count; + buf_len -= count; + if ( count < sizeof(Fore_stats) ) + err = ENOSPC; + } + + /* + * Record amount we're returning as vendor info... + */ + if (err = copyout(&count, &avr->avsp_len, sizeof(int))) + break; + + /* + * Update the reply pointers and lengths + */ + aip->air_buf_addr = buf; + aip->air_buf_len = buf_len; + break; + + default: + err = ENOSYS; /* Operation not supported */ + break; + } + + return (err); +} + + +/* + * Free Fore-specific device resources + * + * Frees all dynamically acquired resources for a device unit. Before + * this function is called, the CP will have been reset and our interrupt + * vectors removed. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + * + */ +void +fore_interface_free(fup) + Fore_unit *fup; +{ + + /* + * Free up all of our allocated memory + */ + fore_xmit_free(fup); + fore_recv_free(fup); + fore_buf_free(fup); + fore_cmd_free(fup); + + /* + * Clear device initialized + */ + if (fup->fu_flags & CUF_INITED) { + fup->fu_flags &= ~CUF_INITED; + } + + if (fup->fu_flags & FUF_STATCMD) { + DMA_FREE_ADDR(fup->fu_stats, fup->fu_statsd, + sizeof(Fore_cp_stats), 0); + fup->fu_flags &= ~FUF_STATCMD; + } + return; +} + diff --git a/sys/dev/hfa/fore_include.h b/sys/dev/hfa/fore_include.h new file mode 100644 index 0000000..b146a3c --- /dev/null +++ b/sys/dev/hfa/fore_include.h @@ -0,0 +1,139 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_include.h,v 1.8 1998/02/19 20:10:18 mks Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * Local driver include files and global declarations + * + */ + +#ifndef _FORE_INCLUDE_H +#define _FORE_INCLUDE_H + +#include <netatm/kern_include.h> + +/* + * If not specified elsewhere, guess which type of bus support we want + */ +#if !(defined(FORE_PCI) || defined(FORE_SBUS)) +#if defined(sparc) +#define FORE_SBUS +#elif defined(__i386__) +#define FORE_PCI +#endif +#endif + +#ifdef FORE_PCI +#include <pci/pcireg.h> +#include <pci/pcivar.h> +#endif + +#include <dev/hfa/fore.h> +#include <dev/hfa/fore_aali.h> +#include <dev/hfa/fore_slave.h> +#include <dev/hfa/fore_stats.h> +#include <dev/hfa/fore_var.h> + +/* + * Global function declarations + */ + /* fore_buffer.c */ +int fore_buf_allocate __P((Fore_unit *)); +void fore_buf_initialize __P((Fore_unit *)); +void fore_buf_supply __P((Fore_unit *)); +void fore_buf_free __P((Fore_unit *)); + + /* fore_command.c */ +int fore_cmd_allocate __P((Fore_unit *)); +void fore_cmd_initialize __P((Fore_unit *)); +void fore_cmd_drain __P((Fore_unit *)); +void fore_cmd_free __P((Fore_unit *)); + + /* fore_if.c */ +int fore_atm_ioctl __P((int, caddr_t, caddr_t)); +void fore_interface_free __P((Fore_unit *)); + + /* fore_init.c */ +void fore_initialize __P((Fore_unit *)); +void fore_initialize_complete __P((Fore_unit *)); + + /* fore_intr.c */ +#if defined(sun) +int fore_poll __P((void)); +#endif +#if (defined(BSD) && (BSD <= 199306)) +int fore_intr __P((void *)); +#else +void fore_intr __P((void *)); +#endif +void fore_watchdog __P((Fore_unit *)); + + /* fore_load.c */ + + /* fore_output.c */ +void fore_output __P((Cmn_unit *, Cmn_vcc *, KBuffer *)); + + /* fore_receive.c */ +int fore_recv_allocate __P((Fore_unit *)); +void fore_recv_initialize __P((Fore_unit *)); +void fore_recv_drain __P((Fore_unit *)); +void fore_recv_free __P((Fore_unit *)); + + /* fore_stats.c */ +int fore_get_stats __P((Fore_unit *)); + + /* fore_timer.c */ +void fore_timeout __P((struct atm_time *)); + + /* fore_transmit.c */ +int fore_xmit_allocate __P((Fore_unit *)); +void fore_xmit_initialize __P((Fore_unit *)); +void fore_xmit_drain __P((Fore_unit *)); +void fore_xmit_free __P((Fore_unit *)); + + /* fore_vcm.c */ +int fore_instvcc __P((Cmn_unit *, Cmn_vcc *)); +int fore_openvcc __P((Cmn_unit *, Cmn_vcc *)); +int fore_closevcc __P((Cmn_unit *, Cmn_vcc *)); + + +/* + * Global variable declarations + */ +extern Fore_device fore_devices[]; +extern Fore_unit *fore_units[]; +extern int fore_nunits; +extern struct stack_defn *fore_services; +extern struct sp_info fore_nif_pool; +extern struct sp_info fore_vcc_pool; +extern struct atm_time fore_timer; + +#endif /* _FORE_INCLUDE_H */ diff --git a/sys/dev/hfa/fore_init.c b/sys/dev/hfa/fore_init.c new file mode 100644 index 0000000..61f4f01 --- /dev/null +++ b/sys/dev/hfa/fore_init.c @@ -0,0 +1,314 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_init.c,v 1.7 1997/05/06 22:09:43 mks Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * Cell Processor (CP) initialization routines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: fore_init.c,v 1.7 1997/05/06 22:09:43 mks Exp $"; +#endif + +#include <dev/hfa/fore_include.h> + + +/* + * Local functions + */ +#ifdef FORE_PCI +static void fore_get_prom __P((Fore_unit *)); +#endif + + +/* + * Begin CP Initialization + * + * This function will poll for the successful downloading and starting of + * the CP microcode program. After the microcode is running, we will allocate + * any needed kernel memory (must do it in non-interrupt mode), build the CP + * queue configurations and issue an Initialize command to the CP. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +void +fore_initialize(fup) + Fore_unit *fup; +{ + Aali *aap; + Init_parms *inp; + caddr_t errmsg; + u_long vers; + + /* + * Must wait until firmware has been downloaded and is running + */ + if (CP_READ(fup->fu_mon->mon_bstat) != BOOT_RUNNING) { + + /* + * Try again later + */ + fup->fu_thandle = + timeout((KTimeout_ret(*) __P((void *)))fore_initialize, + (void *)fup, hz); + return; + } else + callout_handle_init(&fup->fu_thandle); + + /* + * Allocate queues and whatever else is needed + */ + if (fore_xmit_allocate(fup)) { + errmsg = "transmit queue allocation"; + goto failed; + } + if (fore_recv_allocate(fup)) { + errmsg = "receive queue allocation"; + goto failed; + } + if (fore_buf_allocate(fup)) { + errmsg = "buffer supply queue allocation"; + goto failed; + } + if (fore_cmd_allocate(fup)) { + errmsg = "command queue allocation"; + goto failed; + } + + /* + * CP microcode is downloaded - locate shared memory interface + */ + aap = (Aali *)(fup->fu_ram + CP_READ(fup->fu_mon->mon_appl)); + fup->fu_aali = aap; + + /* + * Pick out any interesting info from the microcode + */ + vers = CP_READ(aap->aali_ucode_ver); + if (vers < FORE_MIN_UCODE) { + errmsg = "unsupported microcode version"; + goto failed; + } + sprintf(fup->fu_config.ac_firm_vers, "%d.%d.%d", + (vers >> 16) & 0xff, (vers >> 8) & 0xff, vers & 0xff); + +#ifdef notdef + /* + * Turn on CP debugging + */ + aap->aali_hostlog = 1; +#endif + + /* + * Build the initialization block + */ + inp = &aap->aali_init; + inp->init_numvcc = CP_WRITE(FORE_MAX_VCC); + inp->init_cmd_elem = CP_WRITE(CMD_QUELEN); + inp->init_xmit_elem = CP_WRITE(XMIT_QUELEN); + inp->init_recv_elem = CP_WRITE(RECV_QUELEN); + inp->init_recv_ext = CP_WRITE(RECV_EXTRA_SEGS); + inp->init_xmit_ext = CP_WRITE(XMIT_EXTRA_SEGS); + inp->init_buf1s.bfs_quelen = CP_WRITE(BUF1_SM_QUELEN); + inp->init_buf1s.bfs_bufsize = CP_WRITE(BUF1_SM_SIZE); + inp->init_buf1s.bfs_cppool = CP_WRITE(BUF1_SM_CPPOOL); + inp->init_buf1s.bfs_entsize = CP_WRITE(BUF1_SM_ENTSIZE); + inp->init_buf1l.bfs_quelen = CP_WRITE(BUF1_LG_QUELEN); + inp->init_buf1l.bfs_bufsize = CP_WRITE(BUF1_LG_SIZE); + inp->init_buf1l.bfs_cppool = CP_WRITE(BUF1_LG_CPPOOL); + inp->init_buf1l.bfs_entsize = CP_WRITE(BUF1_LG_ENTSIZE); + inp->init_buf2s.bfs_quelen = CP_WRITE(0); + inp->init_buf2s.bfs_bufsize = CP_WRITE(0); + inp->init_buf2s.bfs_cppool = CP_WRITE(0); + inp->init_buf2s.bfs_entsize = CP_WRITE(0); + inp->init_buf2l.bfs_quelen = CP_WRITE(0); + inp->init_buf2l.bfs_bufsize = CP_WRITE(0); + inp->init_buf2l.bfs_cppool = CP_WRITE(0); + inp->init_buf2l.bfs_entsize = CP_WRITE(0); + + /* + * Enable device interrupts + */ + aap->aali_intr_ena = CP_WRITE(1); + + /* + * Issue the Initialize command to the CP and wait for + * the CP to interrupt to signal completion + */ + inp->init_status = CP_WRITE(QSTAT_PENDING); + inp->init_cmd = CP_WRITE(CMD_INIT | CMD_INTR_REQ); + return; + +failed: + /* + * Initialization failure + */ + fore_interface_free(fup); + log(LOG_ERR, "fore initialization failed: intf=%s%d, err=%s\n", + fup->fu_pif.pif_name, fup->fu_pif.pif_unit, errmsg); + return; +} + + +/* + * Complete CP Initialization + * + * Called after the CP has successfully completed processing of the + * Initialize command. We will now finish off our part of the + * initialization process by setting up all the host-based queue + * management structures. + * + * Called at interrupt level. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +void +fore_initialize_complete(fup) + Fore_unit *fup; +{ + Aali *aap = fup->fu_aali; + + /* + * Log an initialization failure + */ + if (CP_READ(aap->aali_init.init_status) & QSTAT_ERROR) { + + log(LOG_ERR, + "fore initialization failed: intf=%s%d, hbeat=0x%x\n", + fup->fu_pif.pif_name, fup->fu_pif.pif_unit, + CP_READ(aap->aali_heartbeat)); + return; + } + + ATM_DEBUG1("heap=0x%x\n", aap->aali_heap); + ATM_DEBUG1("heaplen=0x%x\n", aap->aali_heaplen); + ATM_DEBUG1("cmd_q=0x%x\n", aap->aali_cmd_q); + ATM_DEBUG1("xmit_q=0x%x\n", aap->aali_xmit_q); + ATM_DEBUG1("recv_q=0x%x\n", aap->aali_recv_q); + ATM_DEBUG1("buf1s_q=0x%x\n", aap->aali_buf1s_q); + ATM_DEBUG1("buf1l_q=0x%x\n", aap->aali_buf1l_q); + ATM_DEBUG1("buf2s_q=0x%x\n", aap->aali_buf2s_q); + ATM_DEBUG1("buf2l_q=0x%x\n", aap->aali_buf2l_q); + + /* + * Initialize all of our queues + */ + fore_xmit_initialize(fup); + fore_recv_initialize(fup); + fore_buf_initialize(fup); + fore_cmd_initialize(fup); + + /* + * Mark device initialization completed + */ + fup->fu_flags |= CUF_INITED; + +#ifdef FORE_PCI + fore_get_prom(fup); +#endif + return; +} + + +#ifdef FORE_PCI +/* + * Get device PROM values from CP + * + * This function will issue a GET_PROM command to the CP in order to + * initiate the DMA transfer of the CP's PROM structure to the host. + * This will be called after CP initialization has completed. + * There is (currently) no retry if this fails. + * + * Called at interrupt level. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + * + */ +static void +fore_get_prom(fup) + Fore_unit *fup; +{ + H_cmd_queue *hcp; + Cmd_queue *cqp; + + /* + * Queue command at end of command queue + */ + hcp = fup->fu_cmd_tail; + if ((*hcp->hcq_status) & QSTAT_FREE) { + + /* + * Queue entry available, so set our view of things up + */ + hcp->hcq_code = CMD_GET_PROM; + hcp->hcq_arg = NULL; + fup->fu_cmd_tail = hcp->hcq_next; + + /* + * Now set the CP-resident queue entry - the CP will grab + * the command when the op-code is set. + */ + cqp = hcp->hcq_cpelem; + (*hcp->hcq_status) = QSTAT_PENDING; + + fup->fu_promd = DMA_GET_ADDR(fup->fu_prom, sizeof(Fore_prom), + FORE_PROM_ALIGN, 0); + if (fup->fu_promd == NULL) { + fup->fu_stats->st_drv.drv_cm_nodma++; + return; + } + cqp->cmdq_prom.prom_buffer = (CP_dma) CP_WRITE(fup->fu_promd); + cqp->cmdq_prom.prom_cmd = CP_WRITE(CMD_GET_PROM | CMD_INTR_REQ); + + } else { + /* + * Command queue full + */ + fup->fu_stats->st_drv.drv_cm_full++; + } + + return; +} +#endif /* FORE_PCI */ + diff --git a/sys/dev/hfa/fore_intr.c b/sys/dev/hfa/fore_intr.c new file mode 100644 index 0000000..f295b62 --- /dev/null +++ b/sys/dev/hfa/fore_intr.c @@ -0,0 +1,268 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_intr.c,v 1.7 1997/05/06 22:09:48 mks Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * Interrupt processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: fore_intr.c,v 1.7 1997/05/06 22:09:48 mks Exp $"; +#endif + +#include <dev/hfa/fore_include.h> + +#if defined(sun) +/* + * Polling interrupt routine + * + * Polling interrupts are handled by calling all interrupt service + * routines for a given level until someone claims to have "handled" the + * interrupt. + * + * Called at interrupt level. + * + * Arguments: + * none + * + * Returns: + * 1 an interrupt has been serviced + * 0 no interrupts serviced + * + */ +int +fore_poll() +{ + int serviced = 0; + int unit; + + /* + * See if any of our devices are interrupting + */ + for ( unit = 0; unit < fore_nunits; unit++ ) + { + Fore_unit *fup = fore_units[unit]; + + if (fup == NULL) + continue; + + serviced += fore_intr((void *)fup); + } + + /* + * Indicate if we handled an interrupt + */ + return (serviced ? 1 : 0); +} +#endif /* defined(sun) */ + + +/* + * Device interrupt routine + * + * Called at interrupt level. + * + * Arguments: + * arg pointer to device unit structure + * + * Returns: + * 1 device interrupt was serviced + * 0 no interrupts serviced + * + */ +#if (defined(BSD) && (BSD <= 199306)) +int +#else +void +#endif +fore_intr(arg) + void *arg; +{ + Fore_unit *fup = arg; + Aali *aap; +#if (defined(BSD) && (BSD <= 199306)) + int serviced = 0; +#endif + + /* + * Try to prevent stuff happening after we've paniced + */ + if (panicstr) { + goto done; + } + + /* + * Get to the microcode shared memory interface + */ + if ((aap = fup->fu_aali) == NULL) + goto done; + + /* + * Has this card issued an interrupt?? + */ +#ifdef FORE_PCI + if (*fup->fu_psr) { +#else + if (aap->aali_intr_sent) { +#endif + + /* + * Indicate that we've serviced an interrupt. + */ +#if (defined(BSD) && (BSD <= 199306)) + serviced = 1; +#endif + + /* + * Clear the device interrupt + */ + switch (fup->fu_config.ac_device) { + +#ifdef FORE_SBUS + case DEV_FORE_SBA200E: + SBA200E_HCR_SET(*fup->fu_ctlreg, SBA200E_CLR_SBUS_INTR); + break; + + case DEV_FORE_SBA200: + *fup->fu_ctlreg = SBA200_CLR_SBUS_INTR; + break; +#endif +#ifdef FORE_PCI + case DEV_FORE_PCA200E: + PCA200E_HCR_SET(*fup->fu_ctlreg, PCA200E_CLR_HBUS_INT); + break; +#endif + + } + aap->aali_intr_sent = CP_WRITE(0); + + /* + * Reset the watchdog timer + */ + fup->fu_timer = FORE_WATCHDOG; + + /* + * Device initialization handled separately + */ + if ((fup->fu_flags & CUF_INITED) == 0) { + + /* + * We're just initializing device now, so see if + * the initialization command has completed + */ + if (CP_READ(aap->aali_init.init_status) & + QSTAT_COMPLETED) + fore_initialize_complete(fup); + + /* + * If we're still not inited, none of the host + * queues are setup yet + */ + if ((fup->fu_flags & CUF_INITED) == 0) + goto done; + } + + /* + * Drain the queues of completed work + */ + fore_cmd_drain(fup); + fore_recv_drain(fup); + fore_xmit_drain(fup); + + /* + * Supply more buffers to the CP + */ + fore_buf_supply(fup); + } + +done: +#if (defined(BSD) && (BSD <= 199306)) + return(serviced); +#else + return; +#endif +} + + +/* + * Watchdog timeout routine + * + * Called when we haven't heard from the card in a while. Just in case + * we missed an interrupt, we'll drain the queues and try to resupply the + * CP with more receive buffers. If the CP is partially wedged, hopefully + * this will be enough to get it going again. + * + * Called with interrupts locked out. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + * + */ +void +fore_watchdog(fup) + Fore_unit *fup; +{ + /* + * Try to prevent stuff happening after we've paniced + */ + if (panicstr) { + return; + } + + /* + * Reset the watchdog timer + */ + fup->fu_timer = FORE_WATCHDOG; + + /* + * If the device is initialized, nudge it (wink, wink) + */ + if (fup->fu_flags & CUF_INITED) { + + /* + * Drain the queues of completed work + */ + fore_cmd_drain(fup); + fore_recv_drain(fup); + fore_xmit_drain(fup); + + /* + * Supply more buffers to the CP + */ + fore_buf_supply(fup); + } + + return; +} diff --git a/sys/dev/hfa/fore_load.c b/sys/dev/hfa/fore_load.c new file mode 100644 index 0000000..4250ddc --- /dev/null +++ b/sys/dev/hfa/fore_load.c @@ -0,0 +1,1618 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_load.c,v 1.12 1998/06/29 21:42:14 mks Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * Loadable kernel module and device identification support + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: fore_load.c,v 1.12 1998/06/29 21:42:14 mks Exp $"; +#endif + +#include <dev/hfa/fore_include.h> + + +/* + * Local functions + */ +static int fore_start __P((void)); +static int fore_stop __P((void)); +static int fore_doload __P((void)); +static int fore_dounload __P((void)); +#ifdef sun +static int fore_identify __P((char *)); +static int fore_attach __P((struct devinfo *)); +#endif +#ifdef __FreeBSD__ +static char * fore_pci_probe __P((pcici_t, pcidi_t)); +static void fore_pci_attach __P((pcici_t, int)); +#if BSD < 199506 +static int fore_pci_shutdown __P((struct kern_devconf *, int)); +#else +static void fore_pci_shutdown __P((int, void *)); +#endif +#endif +static void fore_unattach __P((Fore_unit *)); +static void fore_reset __P((Fore_unit *)); + + +/* + * Local variables + */ +static int fore_inited = 0; + +/* + * Driver entry points + */ +#ifdef sun +static struct dev_ops fore_ops = { + 1, /* revision */ + fore_identify, /* identify */ + fore_attach, /* attach */ + NULL, /* open */ + NULL, /* close */ + NULL, /* read */ + NULL, /* write */ + NULL, /* strategy */ + NULL, /* dump */ + NULL, /* psize */ + NULL, /* ioctl */ + NULL, /* reset */ + NULL /* mmap */ +}; +#endif + +#ifdef __FreeBSD__ +static u_long fore_pci_count = 0; + +static struct pci_device fore_pci_device = { + FORE_DEV_NAME, + fore_pci_probe, + fore_pci_attach, + &fore_pci_count, +#if BSD < 199506 + fore_pci_shutdown +#else + NULL +#endif +}; + +DATA_SET(pcidevice_set, fore_pci_device); +#endif + + +/* + * Initialize driver processing + * + * This will be called during module loading. Not much to do here, as + * we must wait for our identify/attach routines to get called before + * we know what we're in for. + * + * Arguments: + * none + * + * Returns: + * 0 startup was successful + * errno startup failed - reason indicated + * + */ +static int +fore_start() +{ + + /* + * Verify software version + */ + if (atm_version != ATM_VERSION) { + log(LOG_ERR, "version mismatch: fore=%d.%d kernel=%d.%d\n", + ATM_VERS_MAJ(ATM_VERSION), ATM_VERS_MIN(ATM_VERSION), + ATM_VERS_MAJ(atm_version), ATM_VERS_MIN(atm_version)); + return (EINVAL); + } + + /* + * Initialize DMA mapping + */ + DMA_INIT(); + + /* + * Start up watchdog timer + */ + atm_timeout(&fore_timer, ATM_HZ * FORE_TIME_TICK, fore_timeout); + + fore_inited = 1; + + return (0); +} + + +/* + * Halt driver processing + * + * This will be called just prior to unloading the module from memory. + * Everything we've setup since we've been loaded must be undone here. + * + * Arguments: + * none + * + * Returns: + * 0 shutdown was successful + * errno shutdown failed - reason indicated + * + */ +static int +fore_stop() +{ + int err = 0; + int s = splimp(); + int i; + + /* + * Stop the watchdog timer + */ + (void) atm_untimeout(&fore_timer); + + /* + * Clean up each device (if any) + */ + for ( i = 0; i < fore_nunits; i++ ) { + Fore_unit *fup = fore_units[i]; + + if (fup == NULL) + continue; + + /* + * Deregister device from kernel services + */ + if (err = atm_physif_deregister((Cmn_unit *)fup)) { + (void) splx(s); + return (err); + } + + /* + * Unattach the device from the system + */ + fore_unattach(fup); + + /* + * Free any Fore-specific device resources + */ + fore_interface_free(fup); + + /* + * Free the unit structure + */ + atm_dev_free(fup); + fore_units[i] = NULL; + } + + fore_nunits = 0; + + /* + * Now free our global resources + */ + + /* + * Release our storage pools + */ + atm_release_pool(&fore_vcc_pool); + atm_release_pool(&fore_nif_pool); + + /* + * Release all DMA mappings + */ + DMA_RELEASE(); + + fore_inited = 0; + + (void) splx(s); + + return (0); +} + + +#ifdef sun +/* + * Device identify routine + * + * Determine if this driver will support the named device. If we claim to + * support the device, our attach routine will (later) be called for the + * device. + * + * Arguments: + * name pointer to identifier string from device + * + * Returns: + * 1 driver claims support for this device + * 0 device not claimed by this driver + * + */ +static int +fore_identify(name) + char *name; +{ + int ret = 0; + int i = 0; + + /* + * Initialize driver stuff + */ + if (fore_inited == 0) { + if (fore_start()) + return (0); + } + + while (fore_devices[i].fd_name) { + if (strcmp(fore_devices[i].fd_name, name) == 0) { + + /* + * We support this device!! + */ + if (fore_nunits < FORE_MAX_UNITS) { + fore_nunits++; + ret = 1; + } else { + log(LOG_ERR, + "fore_identify: Too many devices\n"); + } + break; + } + i++; + } + return (ret); +} + + +/* + * Device attach routine + * + * Attach a device we've previously claimed to support. Walk through its + * register set and map, as required. Determine what level the device will + * be interrupting at and then register an interrupt handler for it. If we + * succeed, then reset the adapter and read useful info from its PROM. + * Last, register the interface with the kernel ATM services. + * + * Arguments: + * devinfo_p pointer to device information structure + * + * Returns: + * 0 attach was successful + * -1 attach failed + * + */ +static int +fore_attach(devinfo_p) + struct dev_info *devinfo_p; +{ + struct dev_reg *dev_reg_p; + struct dev_intr *dev_intr_p; + Fore_unit *fup; + Atm_config *fcp; + addr_t valp; + int val; + int i; + int err_count = BOOT_LOOPS; + static int unit = 0; + + /* + * Sanity check + */ + if (devinfo_p == NULL) + return (-1); + + /* + * Make sure this isn't a duplicate unit + */ + if (fore_units[unit] != NULL) + return (-1); + + /* + * Allocate a new unit structure + */ + fup = (Fore_unit *) atm_dev_alloc(sizeof(Fore_unit), sizeof(int), 0); + if (fup == NULL) + return (-1); + + /* + * Start initializing it + */ + fup->fu_unit = unit; + fup->fu_mtu = FORE_IFF_MTU; + fup->fu_devinfo = devinfo_p; + fup->fu_vcc_pool = &fore_vcc_pool; + fup->fu_nif_pool = &fore_nif_pool; + fup->fu_ioctl = fore_atm_ioctl; + fup->fu_instvcc = fore_instvcc; + fup->fu_openvcc = fore_openvcc; + fup->fu_closevcc = fore_closevcc; + fup->fu_output = fore_output; + + /* + * Consider this unit assigned + */ + fore_units[unit] = fup; + unit++; + + ATM_DEBUG1("fore_attach: fup=0x%x\n", (int)fup); + ATM_DEBUG2("\tfu_xmit_q=0x%x fu_xmit_head=0x%x\n", + (int)fup->fu_xmit_q, (int)&fup->fu_xmit_head); + ATM_DEBUG2("\tfu_recv_q=0x%x fu_recv_head=0x%x\n", + (int)fup->fu_recv_q, (int)&fup->fu_recv_head); + ATM_DEBUG2("\tfu_buf1s_q=0x%x fu_buf1s_head=0x%x\n", + (int)fup->fu_buf1s_q, (int)&fup->fu_buf1s_head); + ATM_DEBUG2("\tfu_buf1l_q=0x%x fu_buf1l_head=0x%x\n", + (int)fup->fu_buf1l_q, (int)&fup->fu_buf1l_head); + ATM_DEBUG2("\tfu_cmd_q=0x%x fu_cmd_head=0x%x\n", + (int)fup->fu_cmd_q, (int)&fup->fu_cmd_head); + ATM_DEBUG1("\tfu_stats=0x%x\n", + (int)&fup->fu_stats); + + /* + * Tell kernel our unit number + */ + devinfo_p->devi_unit = fup->fu_unit; + + /* + * Figure out what type of device we've got. This should always + * work since we've already done this at identify time! + */ + i = 0; + while (fore_devices[i].fd_name) { + if (strcmp(fore_devices[i].fd_name, devinfo_p->devi_name) == 0) + break; + i++; + } + if (fore_devices[i].fd_name == NULL) + return (-1); + + fup->fu_config.ac_device = fore_devices[i].fd_devtyp; + + /* + * Walk through the OPENPROM register information + * mapping register banks as they are found. + */ + for ( dev_reg_p = devinfo_p->devi_reg, i = 1; + i <= devinfo_p->devi_nreg; i++, ++dev_reg_p ) + { + if ( dev_reg_p == NULL ) + { + /* + * Can't happen... + */ + return ( -1 ); + } + + /* + * Each device type has different register sets + */ + switch (fup->fu_config.ac_device) { + +#ifdef FORE_SBUS + case DEV_FORE_SBA200E: + + switch ( i ) + { + /* + * Host Control Register (HCR) + */ + case 1: + if ( sizeof(Fore_reg) != dev_reg_p->reg_size ) + { + return ( -1 ); + } + fup->fu_ctlreg = (Fore_reg *) + map_regs ( dev_reg_p->reg_addr, + sizeof(Fore_reg), + dev_reg_p->reg_bustype ); + if ( fup->fu_ctlreg == NULL ) + { + return ( -1 ); + } + break; + + /* + * SBus Burst Transfer Configuration Register + */ + case 2: + /* + * Not used + */ + break; + + /* + * SBus Interrupt Level Select Register + */ + case 3: + if ( sizeof (Fore_reg) != dev_reg_p->reg_size ) + { + return ( -1 ); + } + fup->fu_intlvl = (Fore_reg *) + map_regs ( dev_reg_p->reg_addr, + sizeof(Fore_reg), + dev_reg_p->reg_bustype ); + if ( fup->fu_intlvl == NULL ) + { + return ( -1 ); + } + break; + + /* + * i960 RAM + */ + case 4: + fup->fu_ram = (Fore_mem *) + map_regs ( dev_reg_p->reg_addr, + dev_reg_p->reg_size, + dev_reg_p->reg_bustype ); + if ( fup->fu_ram == NULL ) + { + return ( -1 ); + } + fup->fu_ramsize = dev_reg_p->reg_size; + + /* + * Various versions of the Sun PROM mess with + * the reg_addr value in unpredictable (to me, + * at least) ways, so just use the "memoffset" + * property, which should give us the RAM + * offset directly. + */ + val = getprop(devinfo_p->devi_nodeid, + "memoffset", -1); + if (val == -1) { + return (-1); + } + fup->fu_config.ac_ram = val; + fup->fu_config.ac_ramsize = fup->fu_ramsize; + + /* + * Set monitor interface for initializing + */ + fup->fu_mon = (Mon960 *) + (fup->fu_ram + MON960_BASE); + break; + + default: + log(LOG_ERR, + "fore_attach: Too many registers\n"); + return ( -1 ); + } + break; + + case DEV_FORE_SBA200: + + switch ( i ) + { + /* + * Board Control Register (BCR) + */ + case 1: + if ( sizeof(Fore_reg) != dev_reg_p->reg_size ) + { + return ( -1 ); + } + fup->fu_ctlreg = (Fore_reg *) + map_regs ( dev_reg_p->reg_addr, + sizeof(Fore_reg), + dev_reg_p->reg_bustype ); + if ( fup->fu_ctlreg == NULL ) + { + return ( -1 ); + } + break; + + /* + * i960 RAM + */ + case 2: + fup->fu_ram = (Fore_mem *) + map_regs ( dev_reg_p->reg_addr, + dev_reg_p->reg_size, + dev_reg_p->reg_bustype ); + if ( fup->fu_ram == NULL ) + { + return ( -1 ); + } + fup->fu_ramsize = dev_reg_p->reg_size; + + /* + * Various versions of the Sun PROM mess with + * the reg_addr value in unpredictable (to me, + * at least) ways, so just use the "memoffset" + * property, which should give us the RAM + * offset directly. + */ + val = getprop(devinfo_p->devi_nodeid, + "memoffset", -1); + if (val == -1) { + return (-1); + } + fup->fu_config.ac_ram = val; + fup->fu_config.ac_ramsize = fup->fu_ramsize; + + /* + * Set monitor interface for initializing + */ + fup->fu_mon = (Mon960 *) + (fup->fu_ram + MON960_BASE); + break; + + default: + log(LOG_ERR, + "fore_attach: Too many registers\n"); + return ( -1 ); + } + break; +#endif /* FORE_SBUS */ + + default: + log(LOG_ERR, + "fore_attach: Unsupported device type %d\n", + fup->fu_config.ac_device); + return (-1); + } + } + + /* + * Install the device in the interrupt chain. + * + * dev_intr_p may be null IFF devi_nintr is zero. + */ + dev_intr_p = devinfo_p->devi_intr; + for ( i = devinfo_p->devi_nintr; i > 0; --i, ++dev_intr_p ) + { + + if ( dev_intr_p == NULL ) + { + /* + * Can't happen. + */ + return ( -1 ); + } + + /* + * Convert hardware ipl (0-15) into spl level. + */ + if ( ipltospl ( dev_intr_p->int_pri ) > fup->fu_intrpri ) + { + fup->fu_intrpri = ipltospl ( dev_intr_p->int_pri ); + + /* + * If SBA-200E card, set SBus interrupt level + * into board register + */ + if ( fup->fu_intlvl ) { +#if defined(sun4c) + *(fup->fu_intlvl) = dev_intr_p->int_pri; +#elif defined(sun4m) + extern int svimap[]; + + *(fup->fu_intlvl) = + svimap[dev_intr_p->int_pri & 0xf]; +#else + #error PORT ME; +#endif + } + } + + DEVICE_LOCK((Cmn_unit *)fup); + + /* + * Register our interrupt routine. + */ + (void) addintr ( dev_intr_p->int_pri, fore_poll, + devinfo_p->devi_name, devinfo_p->devi_unit ); + + /* + * If we can do DMA (we can), then DVMA routines need + * to know the highest IPL level we will interrupt at. + */ + adddma ( dev_intr_p->int_pri ); + + DEVICE_UNLOCK((Cmn_unit *)fup); + } + + /* + * Poke the hardware...boot the CP and prepare it for downloading + */ + fore_reset(fup); + + switch (fup->fu_config.ac_device) { + +#ifdef FORE_SBUS + case DEV_FORE_SBA200E: + /* + * Enable interrupts + */ + SBA200E_HCR_SET(*fup->fu_ctlreg, SBA200E_SBUS_ENA); + break; +#endif /* FORE_SBUS */ + } + + /* + * Wait for monitor to perform self-test + */ + while (CP_READ(fup->fu_mon->mon_bstat) != BOOT_MONREADY) { + if (CP_READ(fup->fu_mon->mon_bstat) == BOOT_FAILTEST) { + log(LOG_ERR, "fore_attach: Unit %d failed self-test\n", + fup->fu_unit); + return (-1); + + } else if ( --err_count == 0 ) { + log(LOG_ERR, "fore_attach: Unit %d unable to boot\n", + fup->fu_unit); + return (-1); + } + DELAY ( BOOT_DELAY ); + } + + /* + * Write a one line message to the console informing + * that we've attached the device. + */ + report_dev ( devinfo_p ); + + /* + * Get the mac address from the card PROM + */ + val = getprop ( devinfo_p->devi_nodeid, "macaddress1", -1 ); + if ( val != -1 ) { + fup->fu_pif.pif_macaddr.ma_data[0] = val & 0xff; + val = getprop ( devinfo_p->devi_nodeid, "macaddress2", -1 ); + fup->fu_pif.pif_macaddr.ma_data[1] = val & 0xff; + val = getprop ( devinfo_p->devi_nodeid, "macaddress3", -1 ); + fup->fu_pif.pif_macaddr.ma_data[2] = val & 0xff; + val = getprop ( devinfo_p->devi_nodeid, "macaddress4", -1 ); + fup->fu_pif.pif_macaddr.ma_data[3] = val & 0xff; + val = getprop ( devinfo_p->devi_nodeid, "macaddress5", -1 ); + fup->fu_pif.pif_macaddr.ma_data[4] = val & 0xff; + val = getprop ( devinfo_p->devi_nodeid, "macaddress6", -1 ); + fup->fu_pif.pif_macaddr.ma_data[5] = val & 0xff; + } else { + /* + * Newer PROM - mac addresses have been combined. Also, + * macaddrlo2 reflects the board serial number. + */ + val = htonl(getprop(devinfo_p->devi_nodeid, "macaddrlo2", -1)); + KM_COPY ( (caddr_t)&val, + (caddr_t)&fup->fu_pif.pif_macaddr.ma_data[2], + sizeof(val) ); + val = htonl(getprop(devinfo_p->devi_nodeid, "macaddrhi4", -1)); + KM_COPY ( (caddr_t)&val, + (caddr_t)fup->fu_pif.pif_macaddr.ma_data, + sizeof(val) ); + } + + /* + * Setup the adapter config info + */ + fcp = &fup->fu_config; + fcp->ac_vendor = VENDOR_FORE; + fcp->ac_vendapi = VENDAPI_FORE_1; + fcp->ac_macaddr = fup->fu_pif.pif_macaddr; + val = getprop ( devinfo_p->devi_nodeid, "promversion", -1 ); + if ( val == -1 ) { + val = getprop ( devinfo_p->devi_nodeid, "hw-version", -1 ); + } + if (val != -1) { + sprintf(fcp->ac_hard_vers, "%d.%d.%d", + (val >> 16) & 0xff, (val >> 8) & 0xff, val & 0xff); + } else + sprintf(fcp->ac_hard_vers, "Unknown"); + + val = getprop ( devinfo_p->devi_nodeid, "serialnumber", -1 ); + if ( val != -1 ) + fcp->ac_serial = val; + + valp = (addr_t)getlongprop ( devinfo_p->devi_nodeid, "model" ); + if ( valp ) + { + /* + * Media Type + */ + switch (fcp->ac_device) { + +#ifdef FORE_SBUS + case DEV_FORE_SBA200E: + fcp->ac_media = MEDIA_OC3C; + fup->fu_pif.pif_pcr = ATM_PCR_OC3C; + break; + + case DEV_FORE_SBA200: + /* + * Look at the /SSS trailer to determine 4B5B speed + * TAXI-100 = 125; TAXI-140 = 175 + * Assume that OC3 has no /SSS speed identifier. + */ + while (*valp && *valp != '/') + valp++; + if (*valp == NULL) { + fcp->ac_media = MEDIA_OC3C; + fup->fu_pif.pif_pcr = ATM_PCR_OC3C; + } else if (strcmp(valp, "/125") == 0) { + fcp->ac_media = MEDIA_TAXI_100; + fup->fu_pif.pif_pcr = ATM_PCR_TAXI100; + } else { + fcp->ac_media = MEDIA_TAXI_140; + fup->fu_pif.pif_pcr = ATM_PCR_TAXI140; + } + break; +#endif /* FORE_SBUS */ + } + + /* + * Free property space + */ + KM_FREE(valp, getproplen(devinfo_p->devi_nodeid, "model"), 0); + } + + /* + * Bus information + */ + fcp->ac_busslot = +#ifdef SBUS_SIZE + (long)(devinfo_p->devi_reg->reg_addr - SBUS_BASE) / SBUS_SIZE; +#else + sbusslot((u_long)devinfo_p->devi_reg->reg_addr); +#endif + + val = getprop(devinfo_p->devi_parent->devi_nodeid, "burst-sizes", 0); + if (val & SBUS_BURST32) + fcp->ac_bustype = BUS_SBUS_B32; + else + fcp->ac_bustype = BUS_SBUS_B16; + + /* + * Set device capabilities + */ + fup->fu_pif.pif_maxvpi = FORE_MAX_VPI; + fup->fu_pif.pif_maxvci = FORE_MAX_VCI; + + /* + * Register this interface with ATM core services + */ + if ( atm_physif_register + ((Cmn_unit *)fup, FORE_DEV_NAME, fore_services) != 0 ) + { + /* + * Registration failed - back everything out + */ + /* + * Modload calls UNLOAD if it get's a failure - don't + * call fore_unload() here. + */ + return ( -1 ); + } + + /* + * Initialize the CP microcode program. + */ + fore_initialize(fup); + + return (0); +} +#endif /* sun */ + + +#ifdef __FreeBSD__ +/* + * Device probe routine + * + * Determine if this driver will support the identified device. If we claim + * to support the device, our attach routine will (later) be called for the + * device. + * + * Arguments: + * config_id device's PCI configuration ID + * device_id device's PCI Vendor/Device ID + * + * Returns: + * name device identification string + * NULL device not claimed by this driver + * + */ +static char * +fore_pci_probe(config_id, device_id) + pcici_t config_id; + pcidi_t device_id; +{ + + /* + * Initialize driver stuff + */ + if (fore_inited == 0) { + if (fore_start()) + return (NULL); + } + + if ((device_id & 0xffff) != FORE_VENDOR_ID) + return (NULL); + + if (((device_id >> 16) & 0xffff) == FORE_PCA200E_ID) + return ("FORE Systems PCA-200E ATM"); + + return (NULL); +} + + +/* + * Device attach routine + * + * Attach a device we've previously claimed to support. Walk through its + * register set and map, as required. Determine what level the device will + * be interrupting at and then register an interrupt handler for it. If we + * succeed, then reset the adapter and initialize the microcode. + * Last, register the interface with the kernel ATM services. + * + * Arguments: + * config_id device's PCI configuration ID + * unit device unit number + * + * Returns: + * none + * + */ +static void +fore_pci_attach(config_id, unit) + pcici_t config_id; + int unit; +{ + Fore_unit *fup; + vm_offset_t va; + vm_offset_t pa; + pcidi_t device_id; + long val; + int err_count = BOOT_LOOPS; + + /* + * Just checking... + */ + if (unit >= FORE_MAX_UNITS) { + log(LOG_ERR, "%s%d: too many devices\n", + FORE_DEV_NAME, unit); + return; + } + + /* + * Make sure this isn't a duplicate unit + */ + if (fore_units[unit] != NULL) + return; + + /* + * Allocate a new unit structure + */ + fup = (Fore_unit *) atm_dev_alloc(sizeof(Fore_unit), sizeof(int), 0); + if (fup == NULL) + return; + + /* + * Start initializing it + */ + fup->fu_unit = unit; + fup->fu_mtu = FORE_IFF_MTU; + fup->fu_pcitag = config_id; + fup->fu_vcc_pool = &fore_vcc_pool; + fup->fu_nif_pool = &fore_nif_pool; + fup->fu_ioctl = fore_atm_ioctl; + fup->fu_instvcc = fore_instvcc; + fup->fu_openvcc = fore_openvcc; + fup->fu_closevcc = fore_closevcc; + fup->fu_output = fore_output; + callout_handle_init(&fup->fu_thandle); + + /* + * Get our device type + */ + device_id = pci_conf_read ( config_id, PCI_ID_REG ); + switch ((device_id >> 16) & 0xffff) { + + case FORE_PCA200E_ID: + fup->fu_config.ac_device = DEV_FORE_PCA200E; + break; + + default: + fup->fu_config.ac_device = DEV_UNKNOWN; + } + + /* + * Map RAM + */ + if ((pci_map_mem(config_id, PCA200E_PCI_MEMBASE, &va, &pa)) == 0) { + log(LOG_ERR, "%s%d: unable to map memory\n", + FORE_DEV_NAME, unit); + goto failed; + } + fup->fu_ram = (Fore_mem *)va; + fup->fu_ramsize = PCA200E_RAM_SIZE; + fup->fu_mon = (Mon960 *)(fup->fu_ram + MON960_BASE); + fup->fu_ctlreg = (Fore_reg *)(va + PCA200E_HCR_OFFSET); + fup->fu_imask = (Fore_reg *)(va + PCA200E_IMASK_OFFSET); + fup->fu_psr = (Fore_reg *)(va + PCA200E_PSR_OFFSET); + + /* + * Convert Endianess of Slave RAM accesses + */ + val = pci_conf_read(config_id, PCA200E_PCI_MCTL); + val |= PCA200E_MCTL_SWAP; + pci_conf_write(config_id, PCA200E_PCI_MCTL, val); + + /* + * Map interrupt in + */ + if ( !pci_map_int( config_id, fore_intr, fup, &net_imask ) ) { + log(LOG_ERR, "%s%d: unable to map interrupt\n", + FORE_DEV_NAME, unit); + goto failed; + } + + /* + * Poke the hardware - boot the CP and prepare it for downloading + */ + fore_reset(fup); + + /* + * Wait for the monitor to perform self-test + */ + while (CP_READ(fup->fu_mon->mon_bstat) != BOOT_MONREADY) { + if (CP_READ(fup->fu_mon->mon_bstat) == BOOT_FAILTEST) { + log(LOG_ERR, "%s%d: failed self-test\n", + FORE_DEV_NAME, unit); + goto failed; + } else if ( --err_count == 0 ) { + log(LOG_ERR, "%s%d: unable to boot - status=0x%x\n", + FORE_DEV_NAME, unit, + CP_READ(fup->fu_mon->mon_bstat)); + goto failed; + } + DELAY ( BOOT_DELAY ); + } + + /* + * Setup the adapter config info - at least as much as we can + */ + fup->fu_config.ac_vendor = VENDOR_FORE; + fup->fu_config.ac_vendapi = VENDAPI_FORE_1; + fup->fu_config.ac_media = MEDIA_OC3C; + fup->fu_pif.pif_pcr = ATM_PCR_OC3C; + fup->fu_config.ac_bustype = BUS_PCI; + fup->fu_config.ac_busslot = config_id->bus << 8 | config_id->slot; + + /* + * Save device ram info for user-level programs + */ + fup->fu_config.ac_ram = (long)fup->fu_ram; + fup->fu_config.ac_ramsize = fup->fu_ramsize; + + /* + * Set device capabilities + */ + fup->fu_pif.pif_maxvpi = FORE_MAX_VPI; + fup->fu_pif.pif_maxvci = FORE_MAX_VCI; + + /* + * Register this interface with ATM core services + */ + if ( atm_physif_register + ((Cmn_unit *)fup, FORE_DEV_NAME, fore_services) != 0 ) + { + /* + * Registration failed - back everything out + */ + goto failed; + } + + fore_units[unit] = fup; + fore_nunits++; + +#if BSD >= 199506 + /* + * Add hook to our shutdown function + */ + at_shutdown(fore_pci_shutdown, fup, SHUTDOWN_POST_SYNC); +#endif + + /* + * Initialize the CP microcode program. + */ + fore_initialize(fup); + + return; + +failed: + /* + * Unattach the device from the system + */ + fore_unattach(fup); + + /* + * Free any Fore-specific device resources + */ + fore_interface_free(fup); + + atm_dev_free(fup); + + return; +} + + +#if BSD < 199506 +/* + * Device shutdown routine + * + * Arguments: + * kdc pointer to device's configuration table + * force forced shutdown flag + * + * Returns: + * none + * + */ +static int +fore_pci_shutdown(kdc, force) + struct kern_devconf *kdc; + int force; +{ + Fore_unit *fup; + + if (kdc->kdc_unit < fore_nunits) { + + fup = fore_units[kdc->kdc_unit]; + if (fup != NULL) { + fore_reset(fup); + } + } + + (void) dev_detach(kdc); + return (0); +} +#else +/* + * Device shutdown routine + * + * Arguments: + * howto type of shutdown + * fup pointer to device unit structure + * + * Returns: + * none + * + */ +static void +fore_pci_shutdown(howto, fup) + int howto; + void *fup; +{ + + fore_reset((Fore_unit *) fup); + + return; +} +#endif /* BSD < 199506 */ +#endif /* __FreeBSD__ */ + + +/* + * Device unattach routine + * + * Reset the physical device, remove any pending timeouts, + * unmap any register sets, and unregister any interrupts. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +static void +fore_unattach(fup) + Fore_unit *fup; +{ +#ifdef sun + struct dev_info *devinfo_p = fup->fu_devinfo; + struct dev_reg *dev_reg_p; + struct dev_intr *dev_intr_p; +#endif + int i; + + + /* + * Reset the board and return it to cold_start state. + * Hopefully, this will prevent use of resources as + * we're trying to free things up. + */ + fore_reset(fup); + + /* + * Lock out all device interrupts + */ + DEVICE_LOCK((Cmn_unit *)fup); + + /* + * Remove any pending timeout()'s + */ + (void)untimeout((KTimeout_ret(*) __P((void *)))fore_initialize, + (void *)fup, fup->fu_thandle); + +#ifdef sun + /* + * Remove any mappings of the device + */ + for ( dev_reg_p = devinfo_p->devi_reg, i = 1; + i <= devinfo_p->devi_nreg; i++, ++dev_reg_p ) + { + if ( dev_reg_p == NULL ) + { + /* + * Can't happen... + */ + break; + } + + /* + * Each device type has different register sets + */ + switch (fup->fu_config.ac_device) { + +#ifdef FORE_SBUS + case DEV_FORE_SBA200E: + + switch ( i ) + { + /* + * Host Control Register (HCR) + */ + case 1: + unmap_regs((addr_t)fup->fu_ctlreg, + sizeof(Fore_reg)); + break; + + /* + * SBus Burst Transfer Configuration Register + */ + case 2: + /* + * Not used + */ + break; + + /* + * SBus Interrupt Level Select Register + */ + case 3: + unmap_regs((addr_t)fup->fu_intlvl, + sizeof(Fore_reg)); + break; + + /* + * i960 RAM + */ + case 4: + unmap_regs((addr_t)fup->fu_ram, + fup->fu_ramsize); + break; + } + break; + + case DEV_FORE_SBA200: + + switch ( i ) + { + /* + * Board Control Register (BCR) + */ + case 1: + unmap_regs((addr_t)fup->fu_ctlreg, + sizeof(Fore_reg)); + break; + + /* + * i960 RAM + */ + case 2: + unmap_regs((addr_t)fup->fu_ram, + fup->fu_ramsize); + break; + } + break; +#endif /* FORE_SBUS */ + } + } + + /* + * Remove the interrupt vector(s) + */ + dev_intr_p = devinfo_p->devi_intr; + for ( i = devinfo_p->devi_nintr; i > 0; --i, ++dev_intr_p ) + { + if ( dev_intr_p == NULL ) + { + /* + * Can't happen... + */ + break; + } + (void) remintr ( dev_intr_p->int_pri, fore_poll ); + } +#endif /* sun */ + +#ifdef __FreeBSD__ + /* + * Unmap the device interrupt + */ + (void) pci_unmap_int(fup->fu_pcitag); + + /* + * Unmap memory + */ +#ifdef notdef + (void) pci_unmap_mem(fup->fu_pcitag, PCA200E_PCI_MEMBASE); +#endif +#endif /* __FreeBSD__ */ + + DEVICE_UNLOCK((Cmn_unit *)fup); +} + + +/* + * Device reset routine + * + * Reset the physical device + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +static void +fore_reset(fup) + Fore_unit *fup; +{ + int s = splimp(); + + /* + * Reset the board and return it to cold_start state + */ + if (fup->fu_mon) + fup->fu_mon->mon_bstat = CP_WRITE(BOOT_COLDSTART); + + if (fup->fu_ctlreg) { + + switch (fup->fu_config.ac_device) { + +#ifdef FORE_SBUS + case DEV_FORE_SBA200E: + /* + * Reset i960 by setting and clearing RESET + */ + SBA200E_HCR_INIT(*fup->fu_ctlreg, SBA200E_RESET); + SBA200E_HCR_CLR(*fup->fu_ctlreg, SBA200E_RESET); + break; + + case DEV_FORE_SBA200: + /* + * Reset i960 by setting and clearing RESET + * + * SBA200 will NOT reset if bit is OR'd in! + */ + *fup->fu_ctlreg = SBA200_RESET; + *fup->fu_ctlreg = SBA200_RESET_CLR; + break; +#endif /* FORE_SBUS */ +#ifdef FORE_PCI + case DEV_FORE_PCA200E: + /* + * Reset i960 by setting and clearing RESET + */ + PCA200E_HCR_INIT(*fup->fu_ctlreg, PCA200E_RESET); + DELAY(10000); + PCA200E_HCR_CLR(*fup->fu_ctlreg, PCA200E_RESET); + break; + +#endif + } + } + + (void) splx(s); + return; +} + + +#ifndef ATM_LINKED +/* + ******************************************************************* + * + * Loadable Module Support + * + ******************************************************************* + */ + +/* + * Generic module load processing + * + * This function is called by an OS-specific function when this + * module is being loaded. + * + * Arguments: + * none + * + * Returns: + * 0 load was successful + * errno load failed - reason indicated + * + */ +static int +fore_doload() +{ + int err = 0; + + /* + * Start us up + */ + err = fore_start(); + if (err) + /* Problems, clean up */ + (void)fore_stop(); + + return (err); +} + + +/* + * Generic module unload processing + * + * This function is called by an OS-specific function when this + * module is being unloaded. + * + * Arguments: + * none + * + * Returns: + * 0 unload was successful + * errno unload failed - reason indicated + * + */ +static int +fore_dounload() +{ + int err = 0; + + /* + * OK, try to clean up our mess + */ + err = fore_stop(); + + return (err); +} + + +#ifdef sun +/* + * Loadable driver description + */ +static struct vdldrv fore_drv = { + VDMAGIC_DRV, /* Device Driver */ + "fore_mod", /* name */ + &fore_ops, /* dev_ops */ + NULL, /* bdevsw */ + NULL, /* cdevsw */ + 0, /* blockmajor */ + 0 /* charmajor */ +}; + + +/* + * Loadable module support entry point + * + * This is the routine called by the vd driver for all loadable module + * functions for this pseudo driver. This routine name must be specified + * on the modload(1) command. This routine will be called whenever the + * modload(1), modunload(1) or modstat(1) commands are issued for this + * module. + * + * Arguments: + * cmd vd command code + * vdp pointer to vd driver's structure + * vdi pointer to command-specific vdioctl_* structure + * vds pointer to status structure (VDSTAT only) + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +int +fore_mod(cmd, vdp, vdi, vds) + int cmd; + struct vddrv *vdp; + caddr_t vdi; + struct vdstat *vds; +{ + int err = 0; + + switch (cmd) { + + case VDLOAD: + /* + * Module Load + * + * We dont support any user configuration + */ + err = fore_doload(); + if (err == 0) + /* Let vd driver know about us */ + vdp->vdd_vdtab = (struct vdlinkage *)&fore_drv; + break; + + case VDUNLOAD: + /* + * Module Unload + */ + err = fore_dounload(); + break; + + case VDSTAT: + /* + * Module Status + */ + + /* Not much to say at the moment */ + + break; + + default: + log(LOG_ERR, "fore_mod: Unknown vd command 0x%x\n", cmd); + err = EINVAL; + } + + return (err); +} +#endif /* sun */ + +#ifdef __FreeBSD__ +#ifdef notdef + +/* + * Driver entry points + */ +static struct cdevsw fore_cdev = { + (d_open_t *)enodev, /* open */ + (d_close_t *)enodev, /* close */ + NULL, /* read */ + NULL, /* write */ + NULL, /* ioctl */ + NULL, /* stop */ + NULL, /* reset */ + NULL, /* devtotty */ + NULL, /* select */ + NULL, /* mmap */ + NULL /* strategy */ +}; + + +/* + * Loadable device driver module description + */ +#if BSD < 199506 +MOD_DEV("fore_mod", LM_DT_CHAR, -1, (void *)&fore_cdev); +#else +MOD_DEV(fore, LM_DT_CHAR, -1, (void *)&fore_cdev); +#endif + + +/* + * Loadable module support "load" entry point + * + * This is the routine called by the lkm driver whenever the + * modload(1) command is issued for this module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +static int +fore_load(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + return(fore_doload()); +} + + +/* + * Loadable module support "unload" entry point + * + * This is the routine called by the lkm driver whenever the + * modunload(1) command is issued for this module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +static int +fore_unload(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + return(fore_dounload()); +} + + +/* + * Loadable module support entry point + * + * This is the routine called by the lkm driver for all loadable module + * functions for this driver. This routine name must be specified + * on the modload(1) command. This routine will be called whenever the + * modload(1), modunload(1) or modstat(1) commands are issued for this + * module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * ver lkm version + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +int +fore_mod(lkmtp, cmd, ver) + struct lkm_table *lkmtp; + int cmd; + int ver; +{ +#if BSD < 199506 + DISPATCH(lkmtp, cmd, ver, fore_load, fore_unload, nosys); +#else + DISPATCH(lkmtp, cmd, ver, fore_load, fore_unload, lkm_nullcmd); +#endif +} +#endif /* notdef */ +#endif /* __FreeBSD__ */ + +#endif /* ATM_LINKED */ + diff --git a/sys/dev/hfa/fore_output.c b/sys/dev/hfa/fore_output.c new file mode 100644 index 0000000..59c82c9 --- /dev/null +++ b/sys/dev/hfa/fore_output.c @@ -0,0 +1,415 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_output.c,v 1.7 1998/02/19 20:10:34 mks Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * PDU output processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: fore_output.c,v 1.7 1998/02/19 20:10:34 mks Exp $"; +#endif + +#include <dev/hfa/fore_include.h> + + +/* + * Local functions + */ +static KBuffer * fore_xmit_segment __P((Fore_unit *, KBuffer *, + H_xmit_queue *, u_int *, u_int *)); + + +/* + * Output a PDU + * + * This function is called via the common driver code after receiving a + * stack *_DATA* command. The common code has already validated most of + * the request so we just need to check a few more Fore-specific details. + * Then we just build a transmit descriptor request for the PDU and issue + * the command to the CP. + * + * Arguments: + * cup pointer to device common unit + * cvp pointer to common VCC entry + * m pointer to output PDU buffer chain head + * + * Returns: + * none + * + */ +void +fore_output(cup, cvp, m) + Cmn_unit *cup; + Cmn_vcc *cvp; + KBuffer *m; +{ + Fore_unit *fup = (Fore_unit *)cup; + Fore_vcc *fvp = (Fore_vcc *)cvp; + struct vccb *vcp; + H_xmit_queue *hxp; + Xmit_queue *cqp; + Xmit_descr *xdp; + u_int retry, nsegs, pdulen; + int s; + +#ifdef DIAGNOSTIC + if (atm_dev_print) + atm_dev_pdu_print(cup, cvp, m, "fore_output"); +#endif + + vcp = fvp->fv_connvc->cvc_vcc; + + /* + * If we're still waiting for activation to finish, delay for + * a little while before we toss the PDU + */ + if (fvp->fv_state == CVS_INITED) { + retry = 3; + while (retry-- && (fvp->fv_state == CVS_INITED)) + DELAY(1000); + if (fvp->fv_state != CVS_ACTIVE) { + /* + * Activation still hasn't finished, oh well.... + */ + fup->fu_stats->st_drv.drv_xm_notact++; + vcp->vc_oerrors++; + if (vcp->vc_nif) + vcp->vc_nif->nif_if.if_oerrors++; + KB_FREEALL(m); + return; + } + } + + /* + * Queue PDU at end of transmit queue + * + * If queue is full we'll delay a bit before tossing the PDU + */ + s = splnet(); + hxp = fup->fu_xmit_tail; + if (!((*hxp->hxq_status) & QSTAT_FREE)) { + + fup->fu_stats->st_drv.drv_xm_full++; + retry = 3; + do { + DELAY(1000); + + DEVICE_LOCK((Cmn_unit *)fup); + fore_xmit_drain(fup); + DEVICE_UNLOCK((Cmn_unit *)fup); + + } while (--retry && (!((*hxp->hxq_status) & QSTAT_FREE))); + + if (!((*hxp->hxq_status) & QSTAT_FREE)) { + /* + * Queue is still full, bye-bye PDU + */ + fup->fu_pif.pif_oerrors++; + vcp->vc_oerrors++; + if (vcp->vc_nif) + vcp->vc_nif->nif_if.if_oerrors++; + KB_FREEALL(m); + (void) splx(s); + return; + } + } + + /* + * We've got a free transmit queue entry + */ + + /* + * Now build the transmit segment descriptors for this PDU + */ + m = fore_xmit_segment(fup, m, hxp, &nsegs, &pdulen); + if (m == NULL) { + /* + * The build failed, buffer chain has been freed + */ + vcp->vc_oerrors++; + if (vcp->vc_nif) + vcp->vc_nif->nif_if.if_oerrors++; + (void) splx(s); + return; + } + + /* + * Set up the descriptor header + */ + xdp = hxp->hxq_descr; + xdp->xd_cell_hdr = ATM_HDR_SET(vcp->vc_vpi, vcp->vc_vci, 0, 0); + xdp->xd_spec = XDS_SET_SPEC(0, fvp->fv_aal, nsegs, pdulen); + xdp->xd_rate = FORE_DEF_RATE; + + /* + * Everything is ready to go, so officially claim the host queue + * entry and setup the CP-resident queue entry. The CP will grab + * the PDU when the descriptor pointer is set. + */ + fup->fu_xmit_tail = hxp->hxq_next; + hxp->hxq_buf = m; + hxp->hxq_vcc = fvp; + (*hxp->hxq_status) = QSTAT_PENDING; + cqp = hxp->hxq_cpelem; + cqp->cq_descr = (CP_dma) + CP_WRITE((u_long)hxp->hxq_descr_dma | XMIT_SEGS_TO_BLKS(nsegs)); + + (void) splx(s); + + /* + * See if there are any completed queue entries + */ + DEVICE_LOCK((Cmn_unit *)fup); + fore_xmit_drain(fup); + DEVICE_UNLOCK((Cmn_unit *)fup); + + return; +} + + +/* + * Build Transmit Segment Descriptors + * + * This function will take a supplied buffer chain of data to be transmitted + * and build the transmit segment descriptors for the data. This will include + * the dreaded operation of ensuring that the data for each transmit segment + * is full-word aligned and (except for the last segment) is an integral number + * of words in length. If the data isn't already aligned and sized as + * required, then the data must be shifted (copied) into place - a sure + * performance killer. Note that we rely on the fact that all buffer data + * areas are allocated with (at least) full-word alignments/lengths. + * + * If any errors are encountered, the buffer chain will be freed. + * + * Arguments: + * fup pointer to device unit + * m pointer to output PDU buffer chain head + * hxp pointer to host transmit queue entry + * segp pointer to return the number of transmit segments + * lenp pointer to return the pdu length + * + * Returns: + * m build successful, pointer to (possibly new) head of + * output PDU buffer chain + * NULL build failed, buffer chain freed + * + */ +static KBuffer * +fore_xmit_segment(fup, m, hxp, segp, lenp) + Fore_unit *fup; + KBuffer *m; + H_xmit_queue *hxp; + u_int *segp; + u_int *lenp; +{ + Xmit_descr *xdp = hxp->hxq_descr; + Xmit_seg_descr *xsp; + H_dma *sdmap; + KBuffer *m0, *m1, *mprev; + caddr_t cp, bfr; + void *dma; + u_int pdulen, nsegs, len, align; + int compressed = 0; + + m0 = m; + +retry: + xsp = xdp->xd_seg; + sdmap = hxp->hxq_dma; + mprev = NULL; + pdulen = 0; + nsegs = 0; + + /* + * Loop thru each buffer in the chain, performing the necessary + * data positioning and then building a segment descriptor for + * that data. + */ + while (m) { + /* + * Get rid of any zero-length buffers + */ + if (KB_LEN(m) == 0) { + if (mprev) { + KB_UNLINK(m, mprev, m1); + } else { + KB_UNLINKHEAD(m, m1); + m0 = m1; + } + m = m1; + continue; + } + + /* + * Make sure we don't try to use too many segments + */ + if (nsegs >= XMIT_MAX_SEGS) { + /* + * Try to compress buffer chain (but only once) + */ + if (compressed) { + KB_FREEALL(m0); + return (NULL); + } + + fup->fu_stats->st_drv.drv_xm_maxpdu++; + + m = atm_dev_compress(m0); + if (m == NULL) { + return (NULL); + } + + /* + * Build segment descriptors for compressed chain + */ + m0 = m; + compressed = 1; + goto retry; + } + + /* + * Get start of data onto full-word alignment + */ + KB_DATASTART(m, cp, caddr_t); + if (align = ((u_int)cp) & (XMIT_SEG_ALIGN - 1)) { + /* + * Gotta slide the data up + */ + fup->fu_stats->st_drv.drv_xm_segnoal++; + bfr = cp - align; + KM_COPY(cp, bfr, KB_LEN(m)); + KB_HEADMOVE(m, -align); + } else { + /* + * Data already aligned + */ + bfr = cp; + } + + /* + * Now work on getting the data length correct + */ + len = KB_LEN(m); + while ((align = (len & (XMIT_SEG_ALIGN - 1))) && + (m1 = KB_NEXT(m))) { + + /* + * Have to move some data from following buffer(s) + * to word-fill this buffer + */ + u_int ncopy = MIN(XMIT_SEG_ALIGN - align, KB_LEN(m1)); + + if (ncopy) { + /* + * Move data to current buffer + */ + caddr_t dest; + + fup->fu_stats->st_drv.drv_xm_seglen++; + KB_DATASTART(m1, cp, caddr_t); + dest = bfr + len; + KB_HEADADJ(m1, -ncopy); + KB_TAILADJ(m, ncopy); + len += ncopy; + while (ncopy--) { + *dest++ = *cp++; + } + } + + /* + * If we've drained the buffer, free it + */ + if (KB_LEN(m1) == 0) { + KBuffer *m2; + + KB_UNLINK(m1, m, m2); + } + } + + /* + * Finally, build the segment descriptor + */ + + /* + * Round last segment to fullword length (if needed) + */ + if (len & (XMIT_SEG_ALIGN - 1)) + xsp->xsd_len = KB_LEN(m) = + (len + XMIT_SEG_ALIGN) & ~(XMIT_SEG_ALIGN - 1); + else + xsp->xsd_len = KB_LEN(m) = len; + + /* + * Get a DMA address for the data + */ + dma = DMA_GET_ADDR(bfr, xsp->xsd_len, XMIT_SEG_ALIGN, 0); + if (dma == NULL) { + + fup->fu_stats->st_drv.drv_xm_segdma++; + KB_FREEALL(m0); + return (NULL); + } + + /* + * Now we're really ready to call it a segment + */ + *sdmap++ = xsp->xsd_buffer = (H_dma) dma; + + /* + * Bump counters and get ready for next buffer + */ + pdulen += len; + nsegs++; + xsp++; + mprev = m; + m = KB_NEXT(m); + } + + /* + * Validate PDU length + */ + if (pdulen > XMIT_MAX_PDULEN) { + fup->fu_stats->st_drv.drv_xm_maxpdu++; + KB_FREEALL(m0); + return (NULL); + } + + /* + * Return the good news to the caller + */ + *segp = nsegs; + *lenp = pdulen; + + return (m0); +} + diff --git a/sys/dev/hfa/fore_receive.c b/sys/dev/hfa/fore_receive.c new file mode 100644 index 0000000..f9a9d19 --- /dev/null +++ b/sys/dev/hfa/fore_receive.c @@ -0,0 +1,582 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_receive.c,v 1.10 1998/07/17 20:19:35 root Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * Receive queue management + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: fore_receive.c,v 1.10 1998/07/17 20:19:35 root Exp $"; +#endif + +#include <dev/hfa/fore_include.h> + + +/* + * Local functions + */ +static void fore_recv_stack __P((void *, KBuffer *)); + + +/* + * Allocate Receive Queue Data Structures + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * 0 allocations successful + * else allocation failed + */ +int +fore_recv_allocate(fup) + Fore_unit *fup; +{ + caddr_t memp; + + /* + * Allocate non-cacheable memory for receive status words + */ + memp = atm_dev_alloc(sizeof(Q_status) * RECV_QUELEN, + QSTAT_ALIGN, ATM_DEV_NONCACHE); + if (memp == NULL) { + return (1); + } + fup->fu_recv_stat = (Q_status *) memp; + + memp = DMA_GET_ADDR(fup->fu_recv_stat, sizeof(Q_status) * RECV_QUELEN, + QSTAT_ALIGN, ATM_DEV_NONCACHE); + if (memp == NULL) { + return (1); + } + fup->fu_recv_statd = (Q_status *) memp; + + /* + * Allocate memory for receive descriptors + */ + memp = atm_dev_alloc(sizeof(Recv_descr) * RECV_QUELEN, + RECV_DESCR_ALIGN, 0); + if (memp == NULL) { + return (1); + } + fup->fu_recv_desc = (Recv_descr *) memp; + + memp = DMA_GET_ADDR(fup->fu_recv_desc, + sizeof(Recv_descr) * RECV_QUELEN, RECV_DESCR_ALIGN, 0); + if (memp == NULL) { + return (1); + } + fup->fu_recv_descd = (Recv_descr *) memp; + + return (0); +} + + +/* + * Receive Queue Initialization + * + * Allocate and initialize the host-resident receive queue structures + * and then initialize the CP-resident queue structures. + * + * Called at interrupt level. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +void +fore_recv_initialize(fup) + Fore_unit *fup; +{ + Aali *aap = fup->fu_aali; + Recv_queue *cqp; + H_recv_queue *hrp; + Recv_descr *rdp; + Recv_descr *rdp_dma; + Q_status *qsp; + Q_status *qsp_dma; + int i; + + /* + * Point to CP-resident receive queue + */ + cqp = (Recv_queue *)(fup->fu_ram + CP_READ(aap->aali_recv_q)); + + /* + * Point to host-resident receive queue structures + */ + hrp = fup->fu_recv_q; + qsp = fup->fu_recv_stat; + qsp_dma = fup->fu_recv_statd; + rdp = fup->fu_recv_desc; + rdp_dma = fup->fu_recv_descd; + + /* + * Loop thru all queue entries and do whatever needs doing + */ + for (i = 0; i < RECV_QUELEN; i++) { + + /* + * Set queue status word to free + */ + *qsp = QSTAT_FREE; + + /* + * Set up host queue entry and link into ring + */ + hrp->hrq_cpelem = cqp; + hrp->hrq_status = qsp; + hrp->hrq_descr = rdp; + hrp->hrq_descr_dma = rdp_dma; + if (i == (RECV_QUELEN - 1)) + hrp->hrq_next = fup->fu_recv_q; + else + hrp->hrq_next = hrp + 1; + + /* + * Now let the CP into the game + */ + cqp->cq_descr = (CP_dma) CP_WRITE(rdp_dma); + cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma); + + /* + * Bump all queue pointers + */ + hrp++; + qsp++; + qsp_dma++; + rdp++; + rdp_dma++; + cqp++; + } + + /* + * Initialize queue pointers + */ + fup->fu_recv_head = fup->fu_recv_q; + + return; +} + + +/* + * Drain Receive Queue + * + * This function will process all completed entries at the head of the + * receive queue. The received segments will be linked into a received + * PDU buffer chain and it will then be passed up the PDU's VCC stack for + * processing by the next higher protocol layer. + * + * May be called in interrupt state. + * Must be called with interrupts locked out. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +void +fore_recv_drain(fup) + Fore_unit *fup; +{ + H_recv_queue *hrp = NULL; + Recv_descr *rdp; + Recv_seg_descr *rsp; + Buf_handle *bhp; + Fore_vcc *fvp; + struct vccb *vcp; + KBuffer *m, *mhead, *mtail; + caddr_t cp; + u_long hdr, nsegs; + u_int seglen, type0; + int i, pdulen, retries = 0, error; + + /* Silence the compiler */ + mtail = NULL; + type0 = 0; + + /* + * Process each completed entry + */ +retry: + while (*fup->fu_recv_head->hrq_status & QSTAT_COMPLETED) { + + /* + * Get completed entry's receive descriptor + */ + hrp = fup->fu_recv_head; + rdp = hrp->hrq_descr; + +#ifdef VAC + /* + * Cache flush receive descriptor + */ + if (vac) { + vac_flush((addr_t)rdp, sizeof(Recv_descr)); + } +#endif + + hdr = rdp->rd_cell_hdr; + nsegs = rdp->rd_nsegs; + + pdulen = 0; + error = 0; + mhead = NULL; + + /* + * Locate incoming VCC for this PDU + */ + fvp = (Fore_vcc *) atm_dev_vcc_find((Cmn_unit *)fup, + ATM_HDR_GET_VPI(hdr), ATM_HDR_GET_VCI(hdr), VCC_IN); + + /* + * Check for a receive error + * + * Apparently the receive descriptor itself contains valid + * information, but the received pdu data is probably bogus. + * We'll arrange for the receive buffer segments to be tossed. + */ + if (*hrp->hrq_status & QSTAT_ERROR) { + + fup->fu_pif.pif_ierrors++; + if (fvp) { + vcp = fvp->fv_connvc->cvc_vcc; + vcp->vc_ierrors++; + if (vcp->vc_nif) + vcp->vc_nif->nif_if.if_ierrors++; + } + ATM_DEBUG1("fore receive error: hdr=0x%x\n", hdr); + error = 1; + } + + /* + * Build PDU buffer chain from receive segments + */ + for (i = 0, rsp = rdp->rd_seg; i < nsegs; i++, rsp++) { + + bhp = rsp->rsd_handle; + seglen = rsp->rsd_len; + + /* + * Remove buffer from our supplied queue and get + * to the underlying buffer + */ + switch (bhp->bh_type) { + + case BHT_S1_SMALL: + DEQUEUE(bhp, Buf_handle, bh_qelem, + fup->fu_buf1s_bq); + fup->fu_buf1s_cnt--; + m = (KBuffer *) ((caddr_t)bhp - BUF1_SM_HOFF); + KB_DATASTART(m, cp, caddr_t); + DMA_FREE_ADDR(cp, bhp->bh_dma, BUF1_SM_SIZE, 0); + break; + + case BHT_S1_LARGE: + DEQUEUE(bhp, Buf_handle, bh_qelem, + fup->fu_buf1l_bq); + fup->fu_buf1l_cnt--; + m = (KBuffer *) ((caddr_t)bhp - BUF1_LG_HOFF); + KB_DATASTART(m, cp, caddr_t); + DMA_FREE_ADDR(cp, bhp->bh_dma, BUF1_LG_SIZE, 0); + break; + + default: + log(LOG_ERR, + "fore_recv_drain: bhp=0x%x type=0x%x\n", + (int)bhp, bhp->bh_type); + panic("fore_recv_drain: bad buffer type"); + } + + /* + * Toss any zero-length or receive error buffers + */ + if ((seglen == 0) || error) { + KB_FREEALL(m); + continue; + } + + /* + * Link buffer into chain + */ + if (mhead == NULL) { + type0 = bhp->bh_type; + KB_LINKHEAD(m, mhead); + mhead = m; + } else { + KB_LINK(m, mtail); + } + KB_LEN(m) = seglen; + pdulen += seglen; + mtail = m; + + /* + * Flush received buffer data + */ +#ifdef VAC + if (vac) { + addr_t dp; + + KB_DATASTART(m, dp, addr_t); + vac_pageflush(dp); + } +#endif + } + + /* + * Make sure we've got a non-null PDU + */ + if (mhead == NULL) { + goto free_ent; + } + + /* + * We only support user data PDUs (for now) + */ + if (hdr & ATM_HDR_SET_PT(ATM_PT_NONUSER)) { + KB_FREEALL(mhead); + goto free_ent; + } + + /* + * Toss the data if there's no VCC + */ + if (fvp == NULL) { + fup->fu_stats->st_drv.drv_rv_novcc++; + KB_FREEALL(mhead); + goto free_ent; + } + +#ifdef DIAGNOSTIC + if (atm_dev_print) + atm_dev_pdu_print((Cmn_unit *)fup, (Cmn_vcc *)fvp, + mhead, "fore_recv"); +#endif + + /* + * Make sure we have our queueing headroom at the front + * of the buffer chain + */ + if (type0 != BHT_S1_SMALL) { + + /* + * Small buffers already have headroom built-in, but + * if CP had to use a large buffer for the first + * buffer, then we have to allocate a buffer here to + * contain the headroom. + */ + fup->fu_stats->st_drv.drv_rv_nosbf++; + + KB_ALLOCPKT(m, BUF1_SM_SIZE, KB_F_NOWAIT, KB_T_DATA); + if (m == NULL) { + fup->fu_stats->st_drv.drv_rv_nomb++; + KB_FREEALL(mhead); + goto free_ent; + } + + /* + * Put new buffer at head of PDU chain + */ + KB_LINKHEAD(m, mhead); + KB_LEN(m) = 0; + KB_HEADSET(m, BUF1_SM_DOFF); + mhead = m; + } + + /* + * It looks like we've got a valid PDU - count it quick!! + */ + KB_PLENSET(mhead, pdulen); + fup->fu_pif.pif_ipdus++; + fup->fu_pif.pif_ibytes += pdulen; + vcp = fvp->fv_connvc->cvc_vcc; + vcp->vc_ipdus++; + vcp->vc_ibytes += pdulen; + if (vcp->vc_nif) { + vcp->vc_nif->nif_ibytes += pdulen; + vcp->vc_nif->nif_if.if_ipackets++; +#if (defined(BSD) && (BSD >= 199103)) + vcp->vc_nif->nif_if.if_ibytes += pdulen; +#endif + } + + /* + * The STACK_CALL needs to happen at splnet() in order + * for the stack sequence processing to work. Schedule an + * interrupt queue callback at splnet() since we are + * currently at device level. + */ + + /* + * Prepend callback function pointer and token value to buffer. + * We have already guaranteed that the space is available + * in the first buffer. + */ + KB_HEADADJ(mhead, sizeof(atm_intr_func_t) + sizeof(int)); + KB_DATASTART(mhead, cp, caddr_t); + *((atm_intr_func_t *)cp) = fore_recv_stack; + cp += sizeof(atm_intr_func_t); + *((void **)cp) = (void *)fvp; + + /* + * Schedule callback + */ + if (!IF_QFULL(&atm_intrq)) { + IF_ENQUEUE(&atm_intrq, mhead); + SCHED_ATM; + } else { + fup->fu_stats->st_drv.drv_rv_ifull++; + KB_FREEALL(mhead); + goto free_ent; + } + +free_ent: + /* + * Mark this entry free for use and bump head pointer + * to the next entry in the queue + */ + *hrp->hrq_status = QSTAT_FREE; + hrp->hrq_cpelem->cq_descr = + (CP_dma) CP_WRITE((u_long)hrp->hrq_descr_dma); + fup->fu_recv_head = hrp->hrq_next; + } + + /* + * Nearly all of the interrupts generated by the CP will be due + * to PDU reception. However, we may receive an interrupt before + * the CP has completed the status word DMA to host memory. Thus, + * if we haven't processed any PDUs during this interrupt, we will + * wait a bit for completed work on the receive queue, rather than + * having to field an extra interrupt very soon. + */ + if (hrp == NULL) { + if (++retries <= FORE_RECV_RETRY) { + DELAY(FORE_RECV_DELAY); + goto retry; + } + } + + return; +} + + +/* + * Pass Incoming PDU up Stack + * + * This function is called via the core ATM interrupt queue callback + * set in fore_recv_drain(). It will pass the supplied incoming + * PDU up the incoming VCC's stack. + * + * Called at splnet. + * + * Arguments: + * tok token to identify stack instantiation + * m pointer to incoming PDU buffer chain + * + * Returns: + * none + */ +static void +fore_recv_stack(tok, m) + void *tok; + KBuffer *m; +{ + Fore_vcc *fvp = (Fore_vcc *)tok; + int err; + + /* + * Send the data up the stack + */ + STACK_CALL(CPCS_UNITDATA_SIG, fvp->fv_upper, + fvp->fv_toku, fvp->fv_connvc, (int)m, 0, err); + if (err) + KB_FREEALL(m); + + return; +} + + +/* + * Free Receive Queue Data Structures + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +void +fore_recv_free(fup) + Fore_unit *fup; +{ + /* + * We'll just let fore_buf_free() take care of freeing any + * buffers sitting on the receive queue (which are also still + * on the fu_*_bq queue). + */ + if (fup->fu_flags & CUF_INITED) { + } + + /* + * Free the status words + */ + if (fup->fu_recv_stat) { + if (fup->fu_recv_statd) { + DMA_FREE_ADDR(fup->fu_recv_stat, fup->fu_recv_statd, + sizeof(Q_status) * RECV_QUELEN, + ATM_DEV_NONCACHE); + } + atm_dev_free((void *)fup->fu_recv_stat); + fup->fu_recv_stat = NULL; + fup->fu_recv_statd = NULL; + } + + /* + * Free the receive descriptors + */ + if (fup->fu_recv_desc) { + if (fup->fu_recv_descd) { + DMA_FREE_ADDR(fup->fu_recv_desc, fup->fu_recv_descd, + sizeof(Recv_descr) * RECV_QUELEN, 0); + } + atm_dev_free(fup->fu_recv_desc); + fup->fu_recv_desc = NULL; + fup->fu_recv_descd = NULL; + } + + return; +} + diff --git a/sys/dev/hfa/fore_slave.h b/sys/dev/hfa/fore_slave.h new file mode 100644 index 0000000..05e7b5b --- /dev/null +++ b/sys/dev/hfa/fore_slave.h @@ -0,0 +1,191 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_slave.h,v 1.5 1997/08/22 19:45:50 jpt Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * Slave Interface definitions + * + */ + +#ifndef _FORE_SLAVE_H +#define _FORE_SLAVE_H + +/* + * This file contains the (mostly hardware) definitions for each of the + * supported 200-series slave interfaces. + */ + + +/* + * Structure defining the supported FORE 200-series interfaces + */ +struct fore_device { + char *fd_name; /* Device name (from PROM) */ + Atm_device fd_devtyp; /* Device type */ +}; +typedef struct fore_device Fore_device; + + + +/* + * Common definitions + * ------------------ + */ +#define MON960_BASE 0x400 /* Address offset of Mon960 */ +#define AALI_BASE 0x4d40 /* Address offset of Aali */ + +typedef volatile unsigned int Fore_reg; /* Slave control register */ +typedef volatile unsigned char Fore_mem; /* Slave memory */ + + +/* + * SBA-200E SBus Slave Interface + * ----------------------------- + */ + +#define SBA200E_PROM_NAME "FORE,sba-200e" + +/* + * SBA-200E Host Control Register (HCR) + */ +#define SBA200E_READ_BITS 0x1ff /* Valid read data bits */ +#define SBA200E_WRITE_BITS 0x01f /* Valid write data bits */ +#define SBA200E_STICKY_BITS 0x013 /* Sticky data bits */ + +/* Read access */ +#define SBA200E_SBUS_INTR_RD 0x100 /* State of SBus interrupt */ +#define SBA200E_TEST_MODE 0x080 /* Device is in test-mode */ +#define SBA200E_IFIFO_FULL 0x040 /* Input FIFO almost full (when 0) */ +#define SBA200E_ESP_HOLD_RD 0x020 /* State of ESP bus hold */ +#define SBA200E_SBUS_ENA_RD 0x010 /* State of SBus interrupt enable */ +#define SBA200E_OFIFO_FULL 0x008 /* Output FIFO almost full */ +#define SBA200E_SELFTEST_FAIL 0x004 /* i960 self-test failed (when 0) */ +#define SBA200E_HOLD_LOCK_RD 0x002 /* State of i960 hold lock signal */ +#define SBA200E_RESET_RD 0x001 /* State of board reset signal */ + +/* Write access - bit set (clear) */ +#define SBA200E_SBUS_ENA 0x010 /* Enable (disable) SBus interrupts */ +#define SBA200E_CLR_SBUS_INTR 0x008 /* Clear SBus interrupt */ +#define SBA200E_I960_INTR 0x004 /* Issue interrupt to i960 */ +#define SBA200E_HOLD_LOCK 0x002 /* Set (clear) i960 hold lock signal */ +#define SBA200E_RESET 0x001 /* Set (clear) board reset signal */ + +#define SBA200E_HCR_INIT(hcr,bits) \ + ((hcr) = (SBA200E_WRITE_BITS & (bits))) +#define SBA200E_HCR_SET(hcr,bits) \ + ((hcr) = (((hcr) & SBA200E_STICKY_BITS) | (bits))) +#define SBA200E_HCR_CLR(hcr,bits) \ + ((hcr) = ((hcr) & (SBA200E_STICKY_BITS ^ (bits)))) + + + +/* + * SBA-200 SBus Slave Interface + * ---------------------------- + */ + +#define SBA200_PROM_NAME "FORE,sba-200" + +/* + * SBA-200 Board Control Register (BCR) + */ +/* Write access - bit set */ +#define SBA200_CLR_SBUS_INTR 0x04 /* Clear SBus interrupt */ +#define SBA200_RESET 0x01 /* Assert board reset signal */ + +/* Write access - bit clear */ +#define SBA200_RESET_CLR 0x00 /* Clear board reset signal */ + + + +/* + * PCA-200E PCI Bus Slave Interface + * -------------------------------- + */ + +/* + * PCI Identifiers + */ +#define FORE_VENDOR_ID 0x1127 +#define FORE_PCA200E_ID 0x0300 + +/* + * PCA-200E PCI Configuration Space + */ +#define PCA200E_PCI_MEMBASE 0x10 /* Memory base address */ +#define PCA200E_PCI_MCTL 0x40 /* Master control */ + +/* + * PCA-200E Address Space + */ +#define PCA200E_RAM_SIZE 0x100000 +#define PCA200E_HCR_OFFSET 0x100000 +#define PCA200E_IMASK_OFFSET 0x100004 +#define PCA200E_PSR_OFFSET 0x100008 +#define PCA200E_MMAP_SIZE 0x10000c + +/* + * PCA-200E Master Control + */ +#define PCA200E_MCTL_SWAP 0x4000 /* Convert Slave endianess */ + +/* + * PCA-200E Host Control Register (HCR) + */ +#define PCA200E_READ_BITS 0x0ff /* Valid read data bits */ +#define PCA200E_WRITE_BITS 0x01f /* Valid write data bits */ +#define PCA200E_STICKY_BITS 0x000 /* Sticky data bits */ + +/* Read access */ +#define PCA200E_TEST_MODE 0x080 /* Device is in test-mode */ +#define PCA200E_IFIFO_FULL 0x040 /* Input FIFO almost full */ +#define PCA200E_ESP_HOLD_RD 0x020 /* State of ESP hold bus */ +#define PCA200E_OFIFO_FULL 0x010 /* Output FIFO almost full */ +#define PCA200E_HOLD_ACK 0x008 /* State of Hold Ack */ +#define PCA200E_SELFTEST_FAIL 0x004 /* i960 self-test failed */ +#define PCA200E_HOLD_LOCK_RD 0x002 /* State of i960 hold lock signal */ +#define PCA200E_RESET_BD 0x001 /* State of board reset signal */ + +/* Write access */ +#define PCA200E_CLR_HBUS_INT 0x010 /* Clear host bus interrupt */ +#define PCA200E_I960_INTRA 0x008 /* Set slave interrupt A */ +#define PCA200E_I960_INTRB 0x004 /* Set slave interrupt B */ +#define PCA200E_HOLD_LOCK 0x002 /* Set (clear) i960 hold lock signal */ +#define PCA200E_RESET 0x001 /* Set (clear) board reset signal */ + +#define PCA200E_HCR_INIT(hcr,bits) \ + ((hcr) = (PCA200E_WRITE_BITS & (bits))) +#define PCA200E_HCR_SET(hcr,bits) \ + ((hcr) = (bits)) +#define PCA200E_HCR_CLR(hcr,bits) \ + ((hcr) = 0) + +#endif /* _FORE_SLAVE_H */ diff --git a/sys/dev/hfa/fore_stats.c b/sys/dev/hfa/fore_stats.c new file mode 100644 index 0000000..a8271a2 --- /dev/null +++ b/sys/dev/hfa/fore_stats.c @@ -0,0 +1,164 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_stats.c,v 1.5 1997/08/22 18:41:21 mks Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * Device statistics routines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: fore_stats.c,v 1.5 1997/08/22 18:41:21 mks Exp $"; +#endif + +#include <dev/hfa/fore_include.h> + + +/* + * Get device statistics from CP + * + * This function will issue a GET_STATS command to the CP in order to + * initiate the DMA transfer of the CP's statistics structure to the host. + * We will then sleep pending command completion. This must only be called + * from the ioctl system call handler. + * + * Called at splnet. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * 0 stats retrieval successful + * errno stats retrieval failed - reason indicated + * + */ +int +fore_get_stats(fup) + Fore_unit *fup; +{ + H_cmd_queue *hcp; + Cmd_queue *cqp; + int s, sst; + + ATM_DEBUG1("fore_get_stats: fup=0x%x\n", (int)fup); + + /* + * Make sure device has been initialized + */ + if ((fup->fu_flags & CUF_INITED) == 0) { + return (EIO); + } + + /* + * If someone has already initiated a stats request, we'll + * just wait for that one to complete + */ + s = splimp(); + if (fup->fu_flags & FUF_STATCMD) { + +#if (defined(BSD) && (BSD >= 199103)) + sst = tsleep((caddr_t)&fup->fu_stats, PWAIT|PCATCH, "fore", 0); +#else + sst = sleep((caddr_t)&fup->fu_stats, PWAIT|PCATCH); + if (sst != 0) + sst = EINTR; +#endif + (void) splx(s); + return (sst ? sst : fup->fu_stats_ret); + } + + /* + * Limit stats gathering to once a second or so + */ + if (time_second == fup->fu_stats_time) { + (void) splx(s); + return (0); + } else + fup->fu_stats_time = time_second; + + /* + * Queue command at end of command queue + */ + hcp = fup->fu_cmd_tail; + if ((*hcp->hcq_status) & QSTAT_FREE) { + void *dma; + + /* + * Queue entry available, so set our view of things up + */ + hcp->hcq_code = CMD_GET_STATS; + hcp->hcq_arg = NULL; + fup->fu_cmd_tail = hcp->hcq_next; + + /* + * Now set the CP-resident queue entry - the CP will grab + * the command when the op-code is set. + */ + cqp = hcp->hcq_cpelem; + (*hcp->hcq_status) = QSTAT_PENDING; + + dma = DMA_GET_ADDR(fup->fu_stats, sizeof(Fore_cp_stats), + FORE_STATS_ALIGN, 0); + if (dma == NULL) { + fup->fu_stats->st_drv.drv_cm_nodma++; + (void) splx(s); + return (EIO); + } + fup->fu_statsd = dma; + cqp->cmdq_stats.stats_buffer = (CP_dma) CP_WRITE(dma); + + fup->fu_flags |= FUF_STATCMD; + cqp->cmdq_stats.stats_cmd = + CP_WRITE(CMD_GET_STATS | CMD_INTR_REQ); + + /* + * Now wait for command to finish + */ +#if (defined(BSD) && (BSD >= 199103)) + sst = tsleep((caddr_t)&fup->fu_stats, PWAIT|PCATCH, "fore", 0); +#else + sst = sleep((caddr_t)&fup->fu_stats, PWAIT|PCATCH); + if (sst != 0) + sst = EINTR; +#endif + (void) splx(s); + return (sst ? sst : fup->fu_stats_ret); + + } else { + /* + * Command queue full + */ + fup->fu_stats->st_drv.drv_cm_full++; + (void) splx(s); + return (EIO); + } +} + diff --git a/sys/dev/hfa/fore_stats.h b/sys/dev/hfa/fore_stats.h new file mode 100644 index 0000000..3803ddd --- /dev/null +++ b/sys/dev/hfa/fore_stats.h @@ -0,0 +1,83 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_stats.h,v 1.3 1997/05/06 22:10:21 mks Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * Driver statistics definitions + * + */ + +#ifndef _FORE_STATS_H +#define _FORE_STATS_H + + +/* + * Fore Driver Statistics + */ +struct Stats_driver { + u_long drv_xm_notact; /* PDU drops out - VCC not active */ + u_long drv_xm_full; /* Xmit queue full */ + u_long drv_xm_maxpdu; /* PDU drops out - max segment/size */ + u_long drv_xm_segnoal; /* Non-aligned segments */ + u_long drv_xm_seglen; /* Padded length segments */ + u_long drv_xm_segdma; /* PDU drops out - no dma address */ + u_long drv_rv_novcc; /* PDU drops in - no VCC */ + u_long drv_rv_nosbf; /* No small buffers */ + u_long drv_rv_nomb; /* PDU drops in - no buffer */ + u_long drv_rv_ifull; /* PDU drops in - intr queue full */ + u_long drv_bf_segdma; /* Buffer supply - no dma address */ + u_long drv_cm_full; /* Command queue full */ + u_long drv_cm_nodma; /* Command failed - no dma address */ +}; +typedef struct Stats_driver Stats_driver; + + +/* + * Fore Device Statistics + * + * This structure is used by pass all statistics (including CP maintained + * and driver maintained) data to user space (atm command). + */ +struct fore_stats { + Fore_cp_stats st_cpstat; /* CP stats */ + Stats_driver st_drv; /* Driver maintained stats */ +}; +typedef struct fore_stats Fore_stats; + +#define st_taxi st_cpstat.st_cp_taxi +#define st_oc3 st_cpstat.st_cp_oc3 +#define st_atm st_cpstat.st_cp_atm +#define st_aal0 st_cpstat.st_cp_aal0 +#define st_aal4 st_cpstat.st_cp_aal4 +#define st_aal5 st_cpstat.st_cp_aal5 +#define st_misc st_cpstat.st_cp_misc + +#endif /* _FORE_STATS_H */ diff --git a/sys/dev/hfa/fore_timer.c b/sys/dev/hfa/fore_timer.c new file mode 100644 index 0000000..e0d0c0e --- /dev/null +++ b/sys/dev/hfa/fore_timer.c @@ -0,0 +1,97 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_timer.c,v 1.5 1997/05/06 22:10:24 mks Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * Timer processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: fore_timer.c,v 1.5 1997/05/06 22:10:24 mks Exp $"; +#endif + +#include <dev/hfa/fore_include.h> + + +/* + * Process a Fore timer tick + * + * This function is called every FORE_TIME_TICK seconds in order to update + * all of the unit watchdog timers. + * + * Called at splnet. + * + * Arguments: + * tip pointer to fore timer control block + * + * Returns: + * none + * + */ +void +fore_timeout(tip) + struct atm_time *tip; +{ + Fore_unit *fup; + int i; + + + /* + * Schedule next timeout + */ + atm_timeout(&fore_timer, ATM_HZ * FORE_TIME_TICK, fore_timeout); + + /* + * Run through all units, updating each active timer. + * If an expired timer is found, notify that unit. + */ + for (i = 0; i < fore_nunits; i++) { + + if ((fup = fore_units[i]) == NULL) + continue; + + /* + * Decrement timer, if it's active + */ + if (fup->fu_timer && (--fup->fu_timer == 0)) { + + /* + * Timeout occurred - go check out the queues + */ + ATM_DEBUG0("fore_timeout\n"); + DEVICE_LOCK((Cmn_unit *)fup); + fore_watchdog(fup); + DEVICE_UNLOCK((Cmn_unit *)fup); + } + } +} + diff --git a/sys/dev/hfa/fore_transmit.c b/sys/dev/hfa/fore_transmit.c new file mode 100644 index 0000000..744e775 --- /dev/null +++ b/sys/dev/hfa/fore_transmit.c @@ -0,0 +1,371 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_transmit.c,v 1.8 1998/07/17 20:19:37 root Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * Transmit queue management + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: fore_transmit.c,v 1.8 1998/07/17 20:19:37 root Exp $"; +#endif + +#include <dev/hfa/fore_include.h> + + +/* + * Allocate Transmit Queue Data Structures + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * 0 allocations successful + * else allocation failed + */ +int +fore_xmit_allocate(fup) + Fore_unit *fup; +{ + void *memp; + H_xmit_queue *hxp; + int i; + + /* + * Allocate non-cacheable memory for transmit status words + */ + memp = atm_dev_alloc(sizeof(Q_status) * XMIT_QUELEN, + QSTAT_ALIGN, ATM_DEV_NONCACHE); + if (memp == NULL) { + return (1); + } + fup->fu_xmit_stat = (Q_status *) memp; + + memp = DMA_GET_ADDR(fup->fu_xmit_stat, sizeof(Q_status) * XMIT_QUELEN, + QSTAT_ALIGN, ATM_DEV_NONCACHE); + if (memp == NULL) { + return (1); + } + fup->fu_xmit_statd = (Q_status *) memp; + + /* + * Allocate memory for transmit descriptors + * + * We will allocate the transmit descriptors individually rather than + * as a single memory block, which will often be larger than a memory + * page. On some systems (eg. FreeBSD) the physical addresses of + * adjacent virtual memory pages are not contiguous. + */ + hxp = fup->fu_xmit_q; + for (i = 0; i < XMIT_QUELEN; i++, hxp++) { + + /* + * Allocate a transmit descriptor for this queue entry + */ + hxp->hxq_descr = atm_dev_alloc(sizeof(Xmit_descr), + XMIT_DESCR_ALIGN, 0); + if (hxp->hxq_descr == NULL) { + return (1); + } + + hxp->hxq_descr_dma = DMA_GET_ADDR(hxp->hxq_descr, + sizeof(Xmit_descr), XMIT_DESCR_ALIGN, 0); + if (hxp->hxq_descr_dma == NULL) { + return (1); + } + } + + return (0); +} + + +/* + * Transmit Queue Initialization + * + * Allocate and initialize the host-resident transmit queue structures + * and then initialize the CP-resident queue structures. + * + * Called at interrupt level. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +void +fore_xmit_initialize(fup) + Fore_unit *fup; +{ + Aali *aap = fup->fu_aali; + Xmit_queue *cqp; + H_xmit_queue *hxp; + Q_status *qsp; + Q_status *qsp_dma; + int i; + + /* + * Point to CP-resident transmit queue + */ + cqp = (Xmit_queue *)(fup->fu_ram + CP_READ(aap->aali_xmit_q)); + + /* + * Point to host-resident transmit queue structures + */ + hxp = fup->fu_xmit_q; + qsp = fup->fu_xmit_stat; + qsp_dma = fup->fu_xmit_statd; + + /* + * Loop thru all queue entries and do whatever needs doing + */ + for (i = 0; i < XMIT_QUELEN; i++) { + + /* + * Set queue status word to free + */ + *qsp = QSTAT_FREE; + + /* + * Set up host queue entry and link into ring + */ + hxp->hxq_cpelem = cqp; + hxp->hxq_status = qsp; + if (i == (XMIT_QUELEN - 1)) + hxp->hxq_next = fup->fu_xmit_q; + else + hxp->hxq_next = hxp + 1; + + /* + * Now let the CP into the game + */ + cqp->cq_status = (CP_dma) CP_WRITE(qsp_dma); + + /* + * Bump all queue pointers + */ + hxp++; + qsp++; + qsp_dma++; + cqp++; + } + + /* + * Initialize queue pointers + */ + fup->fu_xmit_head = fup->fu_xmit_tail = fup->fu_xmit_q; + + return; +} + + +/* + * Drain Transmit Queue + * + * This function will free all completed entries at the head of the + * transmit queue. Freeing the entry includes releasing the transmit + * buffers (buffer chain) back to the kernel. + * + * May be called in interrupt state. + * Must be called with interrupts locked out. + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +void +fore_xmit_drain(fup) + Fore_unit *fup; +{ + H_xmit_queue *hxp; + H_dma *sdmap; + Fore_vcc *fvp; + struct vccb *vcp; + KBuffer *m; + + /* + * Process each completed entry + */ + while (*fup->fu_xmit_head->hxq_status & QSTAT_COMPLETED) { + + hxp = fup->fu_xmit_head; + + /* + * Release the entry's DMA addresses and buffer chain + */ + for (m = hxp->hxq_buf, sdmap = hxp->hxq_dma; m; + m = KB_NEXT(m), sdmap++) { + caddr_t cp; + + KB_DATASTART(m, cp, caddr_t); + DMA_FREE_ADDR(cp, *sdmap, KB_LEN(m), 0); + } + KB_FREEALL(hxp->hxq_buf); + + /* + * Get VCC over which data was sent (may be null if + * VCC has been closed in the meantime) + */ + fvp = hxp->hxq_vcc; + + /* + * Now collect some statistics + */ + if (*hxp->hxq_status & QSTAT_ERROR) { + /* + * CP ran into problems, not much we can do + * other than record the event + */ + fup->fu_pif.pif_oerrors++; + if (fvp) { + vcp = fvp->fv_connvc->cvc_vcc; + vcp->vc_oerrors++; + if (vcp->vc_nif) + vcp->vc_nif->nif_if.if_oerrors++; + } + } else { + /* + * Good transmission + */ + int len = XDS_GET_LEN(hxp->hxq_descr->xd_spec); + + fup->fu_pif.pif_opdus++; + fup->fu_pif.pif_obytes += len; + if (fvp) { + vcp = fvp->fv_connvc->cvc_vcc; + vcp->vc_opdus++; + vcp->vc_obytes += len; + if (vcp->vc_nif) { + vcp->vc_nif->nif_obytes += len; + vcp->vc_nif->nif_if.if_opackets++; +#if (defined(BSD) && (BSD >= 199103)) + vcp->vc_nif->nif_if.if_obytes += len; +#endif + } + } + } + + /* + * Mark this entry free for use and bump head pointer + * to the next entry in the queue + */ + *hxp->hxq_status = QSTAT_FREE; + fup->fu_xmit_head = hxp->hxq_next; + } + + return; +} + + +/* + * Free Transmit Queue Data Structures + * + * Arguments: + * fup pointer to device unit structure + * + * Returns: + * none + */ +void +fore_xmit_free(fup) + Fore_unit *fup; +{ + H_xmit_queue *hxp; + H_dma *sdmap; + KBuffer *m; + int i; + + /* + * Free any transmit buffers left on the queue + */ + if (fup->fu_flags & CUF_INITED) { + while (*fup->fu_xmit_head->hxq_status != QSTAT_FREE) { + + hxp = fup->fu_xmit_head; + + /* + * Release the entry's DMA addresses and buffer chain + */ + for (m = hxp->hxq_buf, sdmap = hxp->hxq_dma; m; + m = KB_NEXT(m), sdmap++) { + caddr_t cp; + + KB_DATASTART(m, cp, caddr_t); + DMA_FREE_ADDR(cp, *sdmap, KB_LEN(m), 0); + } + KB_FREEALL(hxp->hxq_buf); + + *hxp->hxq_status = QSTAT_FREE; + fup->fu_xmit_head = hxp->hxq_next; + } + } + + /* + * Free the status words + */ + if (fup->fu_xmit_stat) { + if (fup->fu_xmit_statd) { + DMA_FREE_ADDR(fup->fu_xmit_stat, fup->fu_xmit_statd, + sizeof(Q_status) * XMIT_QUELEN, + ATM_DEV_NONCACHE); + } + atm_dev_free((void *)fup->fu_xmit_stat); + fup->fu_xmit_stat = NULL; + fup->fu_xmit_statd = NULL; + } + + /* + * Free the transmit descriptors + */ + hxp = fup->fu_xmit_q; + for (i = 0; i < XMIT_QUELEN; i++, hxp++) { + + /* + * Free the transmit descriptor for this queue entry + */ + if (hxp->hxq_descr_dma) { + DMA_FREE_ADDR(hxp->hxq_descr, hxp->hxq_descr_dma, + sizeof(Xmit_descr), 0); + hxp->hxq_descr_dma = NULL; + } + + if (hxp->hxq_descr) { + atm_dev_free(hxp->hxq_descr); + hxp->hxq_descr = NULL; + } + } + + return; +} + diff --git a/sys/dev/hfa/fore_var.h b/sys/dev/hfa/fore_var.h new file mode 100644 index 0000000..25d2131 --- /dev/null +++ b/sys/dev/hfa/fore_var.h @@ -0,0 +1,269 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_var.h,v 1.8 1998/02/19 20:10:53 mks Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * Host protocol control blocks + * + */ + +#ifndef _FORE_VAR_H +#define _FORE_VAR_H + +/* + * Device VCC Entry + * + * Contains the common and Fore-specific information for each VCC + * which is opened through a Fore device. + */ +struct fore_vcc { + struct cmn_vcc fv_cmn; /* Common VCC stuff */ + Fore_aal fv_aal; /* CP version of AAL */ +}; +typedef struct fore_vcc Fore_vcc; + +#define fv_next fv_cmn.cv_next +#define fv_toku fv_cmn.cv_toku +#define fv_upper fv_cmn.cv_upper +#define fv_connvc fv_cmn.cv_connvc +#define fv_state fv_cmn.cv_state +#define fv_flags fv_cmn.cv_flags + +/* + * VCC Flags + */ +#define FVF_ACTCMD 0x01 /* Activate command issued */ + + +/* + * Host Transmit Queue Element + * + * Defines the host's view of the CP PDU Transmit Queue + */ +struct h_xmit_queue { + struct h_xmit_queue *hxq_next; /* Next element in queue */ + Xmit_queue *hxq_cpelem; /* CP queue element */ + Q_status *hxq_status; /* Element status word */ + Xmit_descr *hxq_descr; /* Element's transmit descriptor */ + Xmit_descr *hxq_descr_dma; /* Element's transmit descriptor */ + Fore_vcc *hxq_vcc; /* Data's VCC */ + KBuffer *hxq_buf; /* Data's buffer chain head */ + H_dma hxq_dma[XMIT_MAX_SEGS]; /* DMA addresses for segments */ +}; +typedef struct h_xmit_queue H_xmit_queue; + + + +/* + * Host Receive Queue Element + * + * Defines the host's view of the CP PDU Receive Queue + */ +struct h_recv_queue { + struct h_recv_queue *hrq_next; /* Next element in queue */ + Recv_queue *hrq_cpelem; /* CP queue element */ + Q_status *hrq_status; /* Element status word */ + Recv_descr *hrq_descr; /* Element's receive descriptor */ + Recv_descr *hrq_descr_dma; /* Element's receive descriptor */ +}; +typedef struct h_recv_queue H_recv_queue; + + + +/* + * Host Buffer Supply Queue Element + * + * Defines the host's view of the CP Buffer Supply Queue + */ +struct h_buf_queue { + struct h_buf_queue *hbq_next; /* Next element in queue */ + Buf_queue *hbq_cpelem; /* CP queue element */ + Q_status *hbq_status; /* Element status word */ + Buf_descr *hbq_descr; /* Element's buffer descriptor array */ + Buf_descr *hbq_descr_dma; /* Element's buffer descriptor array */ +}; +typedef struct h_buf_queue H_buf_queue; + + + +/* + * Host Command Queue Element + * + * Defines the host's view of the CP Command Queue + */ +struct h_cmd_queue { + struct h_cmd_queue *hcq_next; /* Next element in queue */ + Cmd_queue *hcq_cpelem; /* CP queue element */ + Q_status *hcq_status; /* Element status word */ + Cmd_code hcq_code; /* Command code */ + void *hcq_arg; /* Command-specific argument */ +}; +typedef struct h_cmd_queue H_cmd_queue; + + + +/* + * Host Buffer Handle + * + * For each buffer supplied to the CP, there will be one of these structures + * embedded into the non-data portion of the buffer. This will allow us to + * track which buffers are currently "controlled" by the CP. The address of + * this structure will supplied to/returned from the CP as the buffer handle. + */ +struct buf_handle { + Qelem_t bh_qelem; /* Queuing element */ + u_int bh_type; /* Buffer type (see below) */ + H_dma bh_dma; /* Buffer DMA address */ +}; +typedef struct buf_handle Buf_handle; +#define SIZEOF_Buf_handle 16 + +/* + * Buffer Types + */ +#define BHT_S1_SMALL 1 /* Buffer strategy 1, small */ +#define BHT_S1_LARGE 2 /* Buffer strategy 1, large */ +#define BHT_S2_SMALL 3 /* Buffer strategy 2, small */ +#define BHT_S2_LARGE 4 /* Buffer strategy 2, large */ + + + +/* + * Device Unit Structure + * + * Contains all the information for a single device (adapter). + */ +struct fore_unit { + Cmn_unit fu_cmn; /* Common unit stuff */ +#ifdef sun + struct dev_info *fu_devinfo; /* Device node for this unit */ +#endif + Fore_reg *fu_ctlreg; /* Device control register */ +#ifdef FORE_SBUS + Fore_reg *fu_intlvl; /* Interrupt level register */ +#endif +#ifdef FORE_PCI + Fore_reg *fu_imask; /* Interrupt mask register */ + Fore_reg *fu_psr; /* PCI specific register */ + pcici_t fu_pcitag; /* PCI tag */ +#endif + Fore_mem *fu_ram; /* Device RAM */ + u_int fu_ramsize; /* Size of device RAM */ + Mon960 *fu_mon; /* Monitor program interface */ + Aali *fu_aali; /* Microcode program interface */ + u_int fu_timer; /* Watchdog timer value */ + + /* Transmit Queue */ + H_xmit_queue fu_xmit_q[XMIT_QUELEN]; /* Host queue */ + H_xmit_queue *fu_xmit_head; /* Queue head */ + H_xmit_queue *fu_xmit_tail; /* Queue tail */ + Q_status *fu_xmit_stat; /* Status array (host) */ + Q_status *fu_xmit_statd; /* Status array (DMA) */ + + /* Receive Queue */ + H_recv_queue fu_recv_q[RECV_QUELEN]; /* Host queue */ + H_recv_queue *fu_recv_head; /* Queue head */ + Q_status *fu_recv_stat; /* Status array (host) */ + Q_status *fu_recv_statd; /* Status array (DMA) */ + Recv_descr *fu_recv_desc; /* Descriptor array (host) */ + Recv_descr *fu_recv_descd; /* Descriptor array (DMA) */ + + /* Buffer Supply Queue - Strategy 1 Small */ + H_buf_queue fu_buf1s_q[BUF1_SM_QUELEN]; /* Host queue */ + H_buf_queue *fu_buf1s_head; /* Queue head */ + H_buf_queue *fu_buf1s_tail; /* Queue tail */ + Q_status *fu_buf1s_stat; /* Status array (host) */ + Q_status *fu_buf1s_statd;/* Status array (DMA) */ + Buf_descr *fu_buf1s_desc; /* Descriptor array (host) */ + Buf_descr *fu_buf1s_descd;/* Descriptor array (DMA) */ + Queue_t fu_buf1s_bq; /* Queue of supplied buffers */ + u_int fu_buf1s_cnt; /* Count of supplied buffers */ + + /* Buffer Supply Queue - Strategy 1 Large */ + H_buf_queue fu_buf1l_q[BUF1_LG_QUELEN]; /* Host queue */ + H_buf_queue *fu_buf1l_head; /* Queue head */ + H_buf_queue *fu_buf1l_tail; /* Queue tail */ + Q_status *fu_buf1l_stat; /* Status array (host) */ + Q_status *fu_buf1l_statd;/* Status array (DMA) */ + Buf_descr *fu_buf1l_desc; /* Descriptor array (host) */ + Buf_descr *fu_buf1l_descd;/* Descriptor array (DMA) */ + Queue_t fu_buf1l_bq; /* Queue of supplied buffers */ + u_int fu_buf1l_cnt; /* Count of supplied buffers */ + + /* Command Queue */ + H_cmd_queue fu_cmd_q[CMD_QUELEN]; /* Host queue */ + H_cmd_queue *fu_cmd_head; /* Queue head */ + H_cmd_queue *fu_cmd_tail; /* Queue tail */ + Q_status *fu_cmd_stat; /* Status array (host) */ + Q_status *fu_cmd_statd; /* Status array (DMA) */ + + Fore_stats *fu_stats; /* Device statistics buffer */ + Fore_stats *fu_statsd; /* Device statistics buffer (DMA) */ + time_t fu_stats_time; /* Last stats request timestamp */ + int fu_stats_ret; /* Stats request return code */ +#ifdef FORE_PCI + Fore_prom *fu_prom; /* Device PROM buffer */ + Fore_prom *fu_promd; /* Device PROM buffer (DMA) */ +#endif + struct callout_handle fu_thandle; /* Timer handle */ +}; +typedef struct fore_unit Fore_unit; + +#define fu_pif fu_cmn.cu_pif +#define fu_unit fu_cmn.cu_unit +#define fu_flags fu_cmn.cu_flags +#define fu_mtu fu_cmn.cu_mtu +#define fu_open_vcc fu_cmn.cu_open_vcc +#define fu_vcc fu_cmn.cu_vcc +#define fu_intrpri fu_cmn.cu_intrpri +#define fu_savepri fu_cmn.cu_savepri +#define fu_vcc_pool fu_cmn.cu_vcc_pool +#define fu_nif_pool fu_cmn.cu_nif_pool +#define fu_ioctl fu_cmn.cu_ioctl +#define fu_instvcc fu_cmn.cu_instvcc +#define fu_openvcc fu_cmn.cu_openvcc +#define fu_closevcc fu_cmn.cu_closevcc +#define fu_output fu_cmn.cu_output +#define fu_config fu_cmn.cu_config + +/* + * Device flags (in addition to CUF_* flags) + */ +#define FUF_STATCMD 0x80 /* Statistics request in progress */ + + +/* + * Macros to access CP memory + */ +#define CP_READ(x) ntohl((u_long)(x)) +#define CP_WRITE(x) htonl((u_long)(x)) + +#endif /* _FORE_VAR_H */ diff --git a/sys/dev/hfa/fore_vcm.c b/sys/dev/hfa/fore_vcm.c new file mode 100644 index 0000000..3efea6a --- /dev/null +++ b/sys/dev/hfa/fore_vcm.c @@ -0,0 +1,321 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: fore_vcm.c,v 1.7 1998/06/29 21:42:20 mks Exp $ + * + */ + +/* + * FORE Systems 200-Series Adapter Support + * --------------------------------------- + * + * Virtual Channel Management + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: fore_vcm.c,v 1.7 1998/06/29 21:42:20 mks Exp $"; +#endif + +#include <dev/hfa/fore_include.h> + + +/* + * VCC Stack Instantiation + * + * This function is called via the common driver code during a device VCC + * stack instantiation. The common code has already validated some of + * the request so we just need to check a few more Fore-specific details. + * + * Called at splnet. + * + * Arguments: + * cup pointer to device common unit + * cvp pointer to common VCC entry + * + * Returns: + * 0 instantiation successful + * err instantiation failed - reason indicated + * + */ +int +fore_instvcc(cup, cvp) + Cmn_unit *cup; + Cmn_vcc *cvp; +{ + Fore_vcc *fvp = (Fore_vcc *)cvp; + Atm_attributes *ap = &fvp->fv_connvc->cvc_attr; + + /* + * Validate requested AAL + */ + switch (ap->aal.type) { + + case ATM_AAL0: + fvp->fv_aal = FORE_AAL_0; + break; + + case ATM_AAL3_4: + fvp->fv_aal = FORE_AAL_4; + if ((ap->aal.v.aal4.forward_max_SDU_size > FORE_IFF_MTU) || + (ap->aal.v.aal4.backward_max_SDU_size > FORE_IFF_MTU)) + return (EINVAL); + break; + + case ATM_AAL5: + fvp->fv_aal = FORE_AAL_5; + if ((ap->aal.v.aal5.forward_max_SDU_size > FORE_IFF_MTU) || + (ap->aal.v.aal5.backward_max_SDU_size > FORE_IFF_MTU)) + return (EINVAL); + break; + + default: + return (EINVAL); + } + + return (0); +} + + +/* + * Open a VCC + * + * This function is called via the common driver code after receiving a + * stack *_INIT command. The common code has already validated most of + * the request so we just need to check a few more Fore-specific details. + * Then we just issue the command to the CP. Note that we can't wait around + * for the CP to process the command, so we return success for now and abort + * the connection if the command later fails. + * + * Called at splimp. + * + * Arguments: + * cup pointer to device common unit + * cvp pointer to common VCC entry + * + * Returns: + * 0 open successful + * else open failed + * + */ +int +fore_openvcc(cup, cvp) + Cmn_unit *cup; + Cmn_vcc *cvp; +{ + Fore_unit *fup = (Fore_unit *)cup; + Fore_vcc *fvp = (Fore_vcc *)cvp; + H_cmd_queue *hcp; + Cmd_queue *cqp; + struct vccb *vcp; + + vcp = fvp->fv_connvc->cvc_vcc; + + ATM_DEBUG4("fore_openvcc: fup=0x%x, fvp=0x%x, vcc=(%d,%d)\n", + (int)fup, (int)fvp, vcp->vc_vpi, vcp->vc_vci); + + /* + * Validate the VPI and VCI values + */ + if ((vcp->vc_vpi > fup->fu_pif.pif_maxvpi) || + (vcp->vc_vci > fup->fu_pif.pif_maxvci)) { + return (1); + } + + /* + * Only need to tell the CP about incoming VCCs + */ + if ((vcp->vc_type & VCC_IN) == 0) { + DEVICE_LOCK((Cmn_unit *)fup); + fup->fu_open_vcc++; + fvp->fv_state = CVS_ACTIVE; + DEVICE_UNLOCK((Cmn_unit *)fup); + return (0); + } + + /* + * Queue command at end of command queue + */ + hcp = fup->fu_cmd_tail; + if ((*hcp->hcq_status) & QSTAT_FREE) { + + /* + * Queue entry available, so set our view of things up + */ + hcp->hcq_code = CMD_ACT_VCCIN; + hcp->hcq_arg = fvp; + fup->fu_cmd_tail = hcp->hcq_next; + fvp->fv_flags |= FVF_ACTCMD; + + /* + * Now set the CP-resident queue entry - the CP will grab + * the command when the op-code is set. + */ + cqp = hcp->hcq_cpelem; + (*hcp->hcq_status) = QSTAT_PENDING; + cqp->cmdq_act.act_vccid = CP_WRITE(vcp->vc_vci); + if (fvp->fv_aal == FORE_AAL_0) + cqp->cmdq_act.act_batch = CP_WRITE(1); + cqp->cmdq_act.act_spec = CP_WRITE( + ACT_SET_SPEC(BUF_STRAT_1, fvp->fv_aal, + CMD_ACT_VCCIN | CMD_INTR_REQ)); + } else { + /* + * Command queue full + */ + fup->fu_stats->st_drv.drv_cm_full++; + return (1); + } + + return (0); +} + + +/* + * Close a VCC + * + * This function is called via the common driver code after receiving a + * stack *_TERM command. The common code has already validated most of + * the request so we just need to check a few more Fore-specific details. + * Then we just issue the command to the CP. Note that we can't wait around + * for the CP to process the command, so we return success for now and whine + * if the command later fails. + * + * Called at splimp. + * + * Arguments: + * cup pointer to device common unit + * cvp pointer to common VCC entry + * + * Returns: + * 0 close successful + * else close failed + * + */ +int +fore_closevcc(cup, cvp) + Cmn_unit *cup; + Cmn_vcc *cvp; +{ + Fore_unit *fup = (Fore_unit *)cup; + Fore_vcc *fvp = (Fore_vcc *)cvp; + H_xmit_queue *hxp; + H_cmd_queue *hcp; + Cmd_queue *cqp; + struct vccb *vcp; + int i, err = 0; + + vcp = fvp->fv_connvc->cvc_vcc; + + ATM_DEBUG4("fore_closevcc: fup=0x%x, fvp=0x%x, vcc=(%d,%d)\n", + (int)fup, (int)fvp, vcp->vc_vpi, vcp->vc_vci); + + DEVICE_LOCK((Cmn_unit *)fup); + + /* + * Clear any references to this VCC in our transmit queue + */ + for (hxp = fup->fu_xmit_head, i = 0; + (*hxp->hxq_status != QSTAT_FREE) && (i < XMIT_QUELEN); + hxp = hxp->hxq_next, i++) { + if (hxp->hxq_vcc == fvp) { + hxp->hxq_vcc = NULL; + } + } + + /* + * Clear any references to this VCC in our command queue + */ + for (hcp = fup->fu_cmd_head, i = 0; + (*hcp->hcq_status != QSTAT_FREE) && (i < CMD_QUELEN); + hcp = hcp->hcq_next, i++) { + switch (hcp->hcq_code) { + + case CMD_ACT_VCCIN: + case CMD_ACT_VCCOUT: + if (hcp->hcq_arg == fvp) { + hcp->hcq_arg = NULL; + } + break; + } + } + + /* + * If this VCC has been previously activated, then we need to tell + * the CP to deactivate it. + */ + if (fvp->fv_flags & FVF_ACTCMD) { + + /* + * Queue command at end of command queue + */ + hcp = fup->fu_cmd_tail; + if ((*hcp->hcq_status) & QSTAT_FREE) { + + /* + * Queue entry available, so set our view of things up + */ + hcp->hcq_code = CMD_DACT_VCCIN; + hcp->hcq_arg = fvp; + fup->fu_cmd_tail = hcp->hcq_next; + + /* + * Now set the CP-resident queue entry - the CP will + * grab the command when the op-code is set. + */ + cqp = hcp->hcq_cpelem; + (*hcp->hcq_status) = QSTAT_PENDING; + cqp->cmdq_dact.dact_vccid = CP_WRITE(vcp->vc_vci); + cqp->cmdq_dact.dact_cmd = + CP_WRITE(CMD_DACT_VCCIN|CMD_INTR_REQ); + } else { + /* + * Command queue full + * + * If we get here, we'll be getting out-of-sync with + * the CP because we can't (for now at least) do + * anything about close errors in the common code. + * This won't be too bad, since we'll just toss any + * PDUs received from the VCC and the sigmgr's will + * always get open failures when trying to use this + * (vpi,vci)...oh, well...always gotta have that one + * last bug to fix! XXX + */ + fup->fu_stats->st_drv.drv_cm_full++; + err = 1; + } + } + + /* + * Finish up... + */ + if (fvp->fv_state == CVS_ACTIVE) + fup->fu_open_vcc--; + + DEVICE_UNLOCK((Cmn_unit *)fup); + + return (err); +} + diff --git a/sys/netatm/atm.h b/sys/netatm/atm.h new file mode 100644 index 0000000..46dfb86 --- /dev/null +++ b/sys/netatm/atm.h @@ -0,0 +1,651 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm.h,v 1.8 1998/07/30 22:30:43 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * ATM address family definitions + * + */ + +#ifndef _NETATM_ATM_H +#define _NETATM_ATM_H + + +/* + * The definitions in this file are intended to conform to the + * specifications defined in: + * + * The Open Group, Networking Services (XNS) Issue 5 + * + * ATM Transport Protocol Information for Sockets + * + * which is Copyright (c) 1997, The Open Group. + * + * All extensions contained in this file to the base specification + * are denoted with a comment string of "XNS_EXT". + */ + +/* + * ATM socket protocols + */ +#define ATM_PROTO_AAL5 0x5301 /* AAL type 5 protocol */ +#define ATM_PROTO_SSCOP 0x5302 /* SSCOP protocol */ + + +/* + * ATM address defintions + */ +/* + * General format of an ATM address + */ +#define ATM_ADDR_LEN 20 /* Size of address field (XNS_EXT) */ + +struct t_atm_addr { + int8_t address_format; /* Address format (see below) */ + u_int8_t address_length; /* Length of address field */ + u_int8_t address[ATM_ADDR_LEN]; /* Address field */ +}; +typedef struct t_atm_addr Atm_addr; /* XNS_EXT */ + +/* + * ATM address formats + */ +#define T_ATM_ABSENT (-1) /* No address present */ +#define T_ATM_ENDSYS_ADDR 1 /* ATM Endsystem */ +#define T_ATM_NSAP_ADDR 1 /* NSAP */ +#define T_ATM_E164_ADDR 2 /* E.164 */ +#define T_ATM_SPANS_ADDR 3 /* FORE SPANS (XNS_EXT) */ +#define T_ATM_PVC_ADDR 4 /* PVC (VPI,VCI) (XNS_EXT) */ + +/* + * ATM Endsystem / NSAP address format + */ +struct atm_addr_nsap { /* XNS_EXT */ + u_char aan_afi; /* Authority and Format Identifier */ + /* (see below) */ + u_char aan_afspec[12]; /* AFI specific fields */ + u_char aan_esi[6]; /* End System Identifier */ + u_char aan_sel; /* Selector */ +}; +typedef struct atm_addr_nsap Atm_addr_nsap; + +/* + * AFI codes + */ +#define AFI_DCC 0x39 /* DCC ATM Format (XNS_EXT) */ +#define AFI_ICD 0x47 /* ICD ATM Format (XNS_EXT) */ +#define AFI_E164 0x45 /* E.164 ATM Format (XNS_EXT) */ + +/* + * E.164 address format + */ +struct atm_addr_e164 { /* XNS_EXT */ + u_char aae_addr[15]; /* E.164 address */ +}; +typedef struct atm_addr_e164 Atm_addr_e164; + +/* + * SPANS address format + */ +struct atm_addr_spans { /* XNS_EXT */ + u_char aas_addr[8]; /* See SPANS code for specific fields */ +}; +typedef struct atm_addr_spans Atm_addr_spans; + +/* + * PVC address format + */ +struct atm_addr_pvc { /* XNS_EXT */ + u_int8_t aap_vpi[2]; /* VPI */ + u_int8_t aap_vci[2]; /* VCI */ +}; +typedef struct atm_addr_pvc Atm_addr_pvc; + +#define ATM_PVC_GET_VPI(addr) /* XNS_EXT */ \ + ((u_int16_t)(((addr)->aap_vpi[0] << 8) | (addr)->aap_vpi[1])) +#define ATM_PVC_GET_VCI(addr) /* XNS_EXT */ \ + ((u_int16_t)(((addr)->aap_vci[0] << 8) | (addr)->aap_vci[1])) +#define ATM_PVC_SET_VPI(addr,vpi) { /* XNS_EXT */ \ + (addr)->aap_vpi[0] = ((vpi) >> 8) & 0xff; \ + (addr)->aap_vpi[1] = (vpi) & 0xff; \ +} +#define ATM_PVC_SET_VCI(addr,vci) { /* XNS_EXT */ \ + (addr)->aap_vci[0] = ((vci) >> 8) & 0xff; \ + (addr)->aap_vci[1] = (vci) & 0xff; \ +} + + +/* + * ATM service access point (SAP) + * + * A SAP address consists of SAP Vector Elements (SVE). Each SVE consists + * of the following fields: + * o tag - defines the interpretation of the SVE; + * o length - the length of the SVE value field; + * o value - the value associated with the SVE; + * + * All of the possible SAP field values are either defined below + * or in the corresponding option value definitions. + */ + +/* + * ATM Address and Selector SVE + */ +struct t_atm_sap_addr { + int8_t SVE_tag_addr; /* SVE tag (address) */ + int8_t SVE_tag_selector; /* SVE tag (selector) */ + /* Address/selector value */ + int8_t address_format; /* Address format */ + u_int8_t address_length; /* Length of address field */ + u_int8_t address[ATM_ADDR_LEN]; /* Address field */ +}; + +/* + * B-LLI Layer 2 SVE + */ +struct t_atm_sap_layer2 { + int8_t SVE_tag; /* SVE tag */ + u_int8_t ID_type; /* Layer 2 protocol discriminator */ + union { /* Layer 2 protocol */ + u_int8_t simple_ID; /* ITU */ + u_int8_t user_defined_ID;/* User-defined */ + } ID; +}; + +/* + * B-LLI Layer 3 SVE + */ +struct t_atm_sap_layer3 { + int8_t SVE_tag; /* SVE tag */ + u_int8_t ID_type; /* Layer 3 protocol discriminator */ + union { /* Layer 3 protocol */ + u_int8_t simple_ID; /* ITU */ + u_int8_t IPI_ID; /* ISO IPI */ + struct { /* IEEE 802.1 SNAP ID */ + u_int8_t OUI[3]; + u_int8_t PID[2]; + } SNAP_ID; + u_int8_t user_defined_ID;/* User-defined */ + } ID; +}; + +/* + * B_HLI SVE + */ +struct t_atm_sap_appl { + int8_t SVE_tag; /* SVE tag */ + u_int8_t ID_type; /* High Layer type discriminator */ + union { /* High Layer type */ + u_int8_t ISO_ID[8]; /* ISO */ + struct { /* Vendor-specific */ + u_int8_t OUI[3]; + u_int8_t app_ID[4]; + } vendor_ID; + u_int8_t user_defined_ID[8];/* User-defined */ + } ID; +}; + +/* + * ATM SAP (protocol) address structure + */ +struct t_atm_sap { + struct t_atm_sap_addr t_atm_sap_addr; + struct t_atm_sap_layer2 t_atm_sap_layer2; + struct t_atm_sap_layer3 t_atm_sap_layer3; + struct t_atm_sap_appl t_atm_sap_appl; +}; + +/* + * SVE Tag values + */ +#define T_ATM_ABSENT (-1) /* Value field invalid; match none */ +#define T_ATM_PRESENT (-2) /* Value field valid; match value */ +#define T_ATM_ANY (-3) /* Value field invalid; match any */ + + +/* + * ATM socket address + */ +struct sockaddr_atm { /* XNS_EXT */ +#if (defined(BSD) && (BSD >= 199103)) + u_char satm_len; /* Length of socket structure */ + u_char satm_family; /* Address family */ +#else + u_short satm_family; /* Address family */ +#endif + struct t_atm_sap satm_addr; /* Protocol address */ +}; + + +/* + * ATM socket options for use with [gs]etsockopt() + */ +#define T_ATM_SIGNALING 0x5301 /* Option level */ + +#define T_ATM_AAL5 1 /* ATM adaptation layer 5 */ +#define T_ATM_TRAFFIC 2 /* ATM traffic descriptor */ +#define T_ATM_BEARER_CAP 3 /* ATM service capabilities */ +#define T_ATM_BHLI 4 /* Higher-layer protocol */ +#define T_ATM_BLLI 5 /* Lower-layer protocol */ +#define T_ATM_DEST_ADDR 6 /* Call responder's address */ +#define T_ATM_DEST_SUB 7 /* Call responder's subaddress */ +#define T_ATM_ORIG_ADDR 8 /* Call initiator's address */ +#define T_ATM_ORIG_SUB 9 /* Call initiator's subaddress */ +#define T_ATM_CALLER_ID 10 /* Caller's ID attributes */ +#define T_ATM_CAUSE 11 /* Cause of disconection */ +#define T_ATM_QOS 12 /* Quality of service */ +#define T_ATM_TRANSIT 13 /* Choice of public carrier */ +#define T_ATM_ADD_LEAF 14 /* Add leaf to connection */ +#define T_ATM_DROP_LEAF 15 /* Remove leaf from connection */ +#define T_ATM_LEAF_IND 16 /* Indication of leaf status */ +#define T_ATM_NET_INTF 17 /* Network interface XNS_EXT */ +#define T_ATM_LLC 18 /* LLC multiplexing XNS_EXT */ +#define T_ATM_APP_NAME 19 /* Application name XNS_EXT */ + + +/* + * Common socket option values + * + * See API specification for individual option applicability/meaning + */ +#define T_ATM_ABSENT (-1) /* No option value present */ +#define T_ATM_NULL 0 /* Option value is null */ +#define T_NO 0 /* Option is not requested */ +#define T_YES 1 /* Option is requested */ + + +/* + * T_ATM_AAL5 option value structure + */ +struct t_atm_aal5 { + int32_t forward_max_SDU_size; + int32_t backward_max_SDU_size; + int32_t SSCS_type; +}; + +/* + * T_ATM_AAL5 option values + */ + /* SSCS_type */ +#define T_ATM_SSCS_SSCOP_REL 1 /* SSCOP assured operation */ +#define T_ATM_SSCS_SSCOP_UNREL 2 /* SSCOP non-assured operation */ +#define T_ATM_SSCS_FR 4 /* Frame relay */ + + +/* + * T_ATM_TRAFFIC option value structure + */ +struct t_atm_traffic_substruct { + int32_t PCR_high_priority; + int32_t PCR_all_traffic; + int32_t SCR_high_priority; + int32_t SCR_all_traffic; + int32_t MBS_high_priority; + int32_t MBS_all_traffic; + int32_t tagging; +}; + +struct t_atm_traffic { + struct t_atm_traffic_substruct forward; + struct t_atm_traffic_substruct backward; + u_int8_t best_effort; +}; + + +/* + * T_ATM_BEARER_CAP option value structure + */ +struct t_atm_bearer { + u_int8_t bearer_class; + u_int8_t traffic_type; + u_int8_t timing_requirements; + u_int8_t clipping_susceptibility; + u_int8_t connection_configuration; +}; + +/* + * T_ATM_BEARER_CAP option values + */ + /* bearer_class */ +#define T_ATM_CLASS_A 0x01 /* Bearer class A */ +#define T_ATM_CLASS_C 0x03 /* Bearer class C */ +#define T_ATM_CLASS_X 0x10 /* Bearer class X */ + + /* traffic_type */ +#define T_ATM_CBR 0x01 /* Constant bit rate */ +#define T_ATM_VBR 0x02 /* Variable bit rate */ + + /* timing_requirements */ +#define T_ATM_END_TO_END 0x01 /* End-to-end timing required */ +#define T_ATM_NO_END_TO_END 0x02 /* End-to-end timing not required */ + + /* connection_configuration */ +#define T_ATM_1_TO_1 0x00 /* Point-to-point connection */ +#define T_ATM_1_TO_MANY 0x01 /* Point-to-multipoint connection */ + + +/* + * T_ATM_BHLI option value structure + */ +struct t_atm_bhli { + int32_t ID_type; + union { + u_int8_t ISO_ID[8]; + struct { + u_int8_t OUI[3]; + u_int8_t app_ID[4]; + } vendor_ID; + u_int8_t user_defined_ID[8]; + } ID; +}; + +/* + * T_ATM_BHLI option values + */ + /* ID_type */ +#define T_ATM_ISO_APP_ID 0 /* ISO codepoint */ +#define T_ATM_USER_APP_ID 1 /* User-specific codepoint */ +#define T_ATM_VENDOR_APP_ID 3 /* Vendor-specific codepoint */ + +/* + * T_ATM_BLLI option value structure + */ +struct t_atm_blli { + struct { + int8_t ID_type; + union { + u_int8_t simple_ID; + u_int8_t user_defined_ID; + } ID; + int8_t mode; + int8_t window_size; + } layer_2_protocol; + struct { + int8_t ID_type; + union { + u_int8_t simple_ID; + int32_t IPI_ID; + struct { + u_int8_t OUI[3]; + u_int8_t PID[2]; + } SNAP_ID; + u_int8_t user_defined_ID; + } ID; + int8_t mode; + int8_t packet_size; + int8_t window_size; + } layer_3_protocol; +}; + + +/* + * T_ATM_BLLI option values + */ + /* layer_[23]_protocol.ID_type */ +#define T_ATM_SIMPLE_ID 1 /* ID via ITU encoding */ +#define T_ATM_IPI_ID 2 /* ID via ISO/IEC TR 9577 */ +#define T_ATM_SNAP_ID 3 /* ID via SNAP */ +#define T_ATM_USER_ID 4 /* ID via user codepoints */ + + /* layer_[23]_protocol.mode */ +#define T_ATM_BLLI_NORMAL_MODE 1 +#define T_ATM_BLLI_EXTENDED_MODE 2 + + /* layer_2_protocol.simple_ID */ +#define T_ATM_BLLI2_I1745 1 /* I.1745 */ +#define T_ATM_BLLI2_Q921 2 /* Q.921 */ +#define T_ATM_BLLI2_X25_LINK 6 /* X.25, link layer */ +#define T_ATM_BLLI2_X25_MLINK 7 /* X.25, multilink */ +#define T_ATM_BLLI2_LAPB 8 /* Extended LAPB */ +#define T_ATM_BLLI2_HDLC_ARM 9 /* I.4335, ARM */ +#define T_ATM_BLLI2_HDLC_NRM 10 /* I.4335, NRM */ +#define T_ATM_BLLI2_HDLC_ABM 11 /* I.4335, ABM */ +#define T_ATM_BLLI2_I8802 12 /* I.8802 */ +#define T_ATM_BLLI2_X75 13 /* X.75 */ +#define T_ATM_BLLI2_Q922 14 /* Q.922 */ +#define T_ATM_BLLI2_I7776 17 /* I.7776 */ + + /* layer_3_protocol.simple_ID */ +#define T_ATM_BLLI3_X25 6 /* X.25 */ +#define T_ATM_BLLI3_I8208 7 /* I.8208 */ +#define T_ATM_BLLI3_X223 8 /* X.223 */ +#define T_ATM_BLLI3_I8473 9 /* I.8473 */ +#define T_ATM_BLLI3_T70 10 /* T.70 */ +#define T_ATM_BLLI3_I9577 11 /* I.9577 */ + + /* layer_3_protocol.packet_size */ +#define T_ATM_PACKET_SIZE_16 4 +#define T_ATM_PACKET_SIZE_32 5 +#define T_ATM_PACKET_SIZE_64 6 +#define T_ATM_PACKET_SIZE_128 7 +#define T_ATM_PACKET_SIZE_256 8 +#define T_ATM_PACKET_SIZE_512 9 +#define T_ATM_PACKET_SIZE_1024 10 +#define T_ATM_PACKET_SIZE_2048 11 +#define T_ATM_PACKET_SIZE_4096 12 + + +/* + * T_ATM_CALLER_ID option value structure + */ +struct t_atm_caller_id { + int8_t presentation; + u_int8_t screening; +}; + +/* + * T_ATM_CALLER_ID option values + */ + /* presentation */ +#define T_ATM_PRES_ALLOWED 0 +#define T_ATM_PRES_RESTRICTED 1 +#define T_ATM_PRES_UNAVAILABLE 2 + /* screening */ +#define T_ATM_USER_ID_NOT_SCREENED 0 +#define T_ATM_USER_ID_PASSED_SCREEN 1 +#define T_ATM_USER_ID_FAILED_SCREEN 2 +#define T_ATM_NETWORK_PROVIDED_ID 3 + + +/* + * T_ATM_CAUSE option value structure + */ +struct t_atm_cause { + int8_t coding_standard; + u_int8_t location; + u_int8_t cause_value; + u_int8_t diagnostics[4]; +}; + +/* + * T_ATM_CAUSE option values + */ + /* coding_standard */ +#define T_ATM_ITU_CODING 0 +#define T_ATM_NETWORK_CODING 3 + + /* location */ +#define T_ATM_LOC_USER 0 +#define T_ATM_LOC_LOCAL_PRIVATE_NET 1 +#define T_ATM_LOC_LOCAL_PUBLIC_NET 2 +#define T_ATM_LOC_TRANSIT_NET 3 +#define T_ATM_LOC_REMOTE_PUBLIC_NET 4 +#define T_ATM_LOC_REMOTE_PRIVATE_NET 5 +#define T_ATM_LOC_INTERNATIONAL_NET 7 +#define T_ATM_LOC_BEYOND_INTERWORKING 10 + + /* cause_value */ +#define T_ATM_CAUSE_UNALLOCATED_NUMBER 1 +#define T_ATM_CAUSE_NO_ROUTE_TO_TRANSIT_NETWORK 2 +#define T_ATM_CAUSE_NO_ROUTE_TO_DESTINATION 3 +#define T_ATM_CAUSE_NORMAL_CALL_CLEARING 16 +#define T_ATM_CAUSE_USER_BUSY 17 +#define T_ATM_CAUSE_NO_USER_RESPONDING 18 +#define T_ATM_CAUSE_CALL_REJECTED 21 +#define T_ATM_CAUSE_NUMBER_CHANGED 22 +#define T_ATM_CAUSE_ALL_CALLS_WITHOUT_CALLER_ID_REJECTED 23 +#define T_ATM_CAUSE_DESTINATION_OUT_OF_ORDER 27 +#define T_ATM_CAUSE_INVALID_NUMBER_FORMAT 28 +#define T_ATM_CAUSE_RESPONSE_TO_STATUS_ENQUIRY 30 +#define T_ATM_CAUSE_UNSPECIFIED_NORMAL 31 +#define T_ATM_CAUSE_REQUESTED_VPCI_VCI_NOT_AVAILABLE 35 +#define T_ATM_CAUSE_VPCI_VCI_ASSIGNMENT_FAILURE 36 +#define T_ATM_CAUSE_USER_CELL_RATE_NOT_AVAILABLE 37 +#define T_ATM_CAUSE_NETWORK_OUT_OF_ORDER 38 +#define T_ATM_CAUSE_TEMPORARY_FAILURE 41 +#define T_ATM_CAUSE_ACCESS_INFO_DISCARDED 43 +#define T_ATM_CAUSE_NO_VPCI_VCI_AVAILABLE 45 +#define T_ATM_CAUSE_UNSPECIFIED_RESOURCE_UNAVAILABLE 47 +#define T_ATM_CAUSE_QUALITY_OF_SERVICE_UNAVAILABLE 49 +#define T_ATM_CAUSE_BEARER_CAPABILITY_NOT_AUTHORIZED 57 +#define T_ATM_CAUSE_BEARER_CAPABILITY_UNAVAILABLE 58 +#define T_ATM_CAUSE_SERVICE_OR_OPTION_UNAVAILABLE 63 +#define T_ATM_CAUSE_BEARER_CAPABILITY_NOT_IMPLEMENTED 65 +#define T_ATM_CAUSE_INVALID_TRAFFIC_PARAMETERS 73 +#define T_ATM_CAUSE_AAL_PARAMETERS_NOT_SUPPORTED 78 +#define T_ATM_CAUSE_INVALID_CALL_REFERENCE_VALUE 81 +#define T_ATM_CAUSE_IDENTIFIED_CHANNEL_DOES_NOT_EXIST 82 +#define T_ATM_CAUSE_INCOMPATIBLE_DESTINATION 88 +#define T_ATM_CAUSE_INVALID_ENDPOINT_REFERENCE 89 +#define T_ATM_CAUSE_INVALID_TRANSIT_NETWORK_SELECTION 91 +#define T_ATM_CAUSE_TOO_MANY_PENDING_ADD_PARTY_REQUESTS 92 +#define T_ATM_CAUSE_MANDITORY_INFO_ELEMENT_MISSING 96 +#define T_ATM_CAUSE_MESSAGE_TYPE_NOT_IMPLEMENTED 97 +#define T_ATM_CAUSE_INFO_ELEMENT_NOT_IMPLEMENTED 99 +#define T_ATM_CAUSE_INVALID_INFO_ELEMENT_CONTENTS 100 +#define T_ATM_CAUSE_MESSAGE_INCOMPATIBLE_WITH_CALL_STATE 101 +#define T_ATM_CAUSE_RECOVERY_ON_TIMER_EXPIRY 102 +#define T_ATM_CAUSE_INCORRECT_MESSAGE_LENGTH 104 +#define T_ATM_CAUSE_UNSPECIFIED_PROTOCOL_ERROR 111 + + +/* + * T_ATM_QOS option value structure + */ +struct t_atm_qos_substruct { + int32_t qos_class; +}; + +struct t_atm_qos { + int8_t coding_standard; + struct t_atm_qos_substruct forward; + struct t_atm_qos_substruct backward; +}; + +/* + * T_ATM_QOS option values + */ + /* qos_class */ +#define T_ATM_QOS_CLASS_0 0 +#define T_ATM_QOS_CLASS_1 1 +#define T_ATM_QOS_CLASS_2 2 +#define T_ATM_QOS_CLASS_3 3 +#define T_ATM_QOS_CLASS_4 4 + + +/* + * T_ATM_TRANSIT structure + */ +#define T_ATM_MAX_NET_ID 4 /* XNS_EXT */ +struct t_atm_transit { + u_int8_t length; + u_int8_t network_id[T_ATM_MAX_NET_ID]; +}; + + +/* + * T_ATM_ADD_LEAF option value structure + */ +struct t_atm_add_leaf { + int32_t leaf_ID; + struct t_atm_addr leaf_address; +}; + + +/* + * T_ATM_DROP_LEAF option value structure + */ +struct t_atm_drop_leaf { + int32_t leaf_ID; + int32_t reason; +}; + +/* + * T_ATM_LEAF_IND option value structure + */ +struct t_atm_leaf_ind { + int32_t status; + int32_t leaf_ID; + int32_t reason; +}; + +/* + * T_ATM_LEAF_IND option values + */ + /* status */ +#define T_LEAF_NOCHANGE 0 +#define T_LEAF_CONNECTED 1 +#define T_LEAF_DISCONNECTED 2 + +/* + * T_ATM_NET_INTF option value structure (XNS_EXT) + */ +struct t_atm_net_intf { /* XNS_EXT */ + char net_intf[IFNAMSIZ]; +}; + +/* + * T_ATM_LLC option value structure (XNS_EXT) + */ +#define T_ATM_LLC_MIN_LEN 3 +#define T_ATM_LLC_MAX_LEN 8 + +struct t_atm_llc { /* XNS_EXT */ + u_int8_t flags; /* LLC flags (see below) */ + u_int8_t llc_len; /* Length of LLC information */ + u_int8_t llc_info[T_ATM_LLC_MAX_LEN]; /* LLC information */ +}; + +/* + * T_ATM_LLC option values + */ + /* flags */ +#define T_ATM_LLC_SHARING 0x01 /* LLC sharing allowed */ + +/* + * T_ATM_APP_NAME option value structure (XNS_EXT) + */ +#define T_ATM_APP_NAME_LEN 8 +struct t_atm_app_name { /* XNS_EXT */ + char app_name[T_ATM_APP_NAME_LEN]; +}; + +#endif /* _NETATM_ATM_H */ diff --git a/sys/netatm/atm_aal5.c b/sys/netatm/atm_aal5.c new file mode 100644 index 0000000..c0e8fe4 --- /dev/null +++ b/sys/netatm/atm_aal5.c @@ -0,0 +1,905 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_aal5.c,v 1.4 1998/07/30 22:30:46 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * ATM AAL5 socket protocol processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_aal5.c,v 1.4 1998/07/30 22:30:46 mks Exp $"; +#endif + +#include <netatm/kern_include.h> +#include <sys/stat.h> + + +/* + * Global variables + */ +u_long atm_aal5_sendspace = 64 * 1024; /* XXX */ +u_long atm_aal5_recvspace = 64 * 1024; /* XXX */ + + +/* + * Local functions + */ +static int atm_aal5_attach __P((struct socket *, int, struct proc *)); +static int atm_aal5_detach __P((struct socket *)); +static int atm_aal5_bind __P((struct socket *, struct sockaddr *, + struct proc *)); +static int atm_aal5_listen __P((struct socket *, struct proc *)); +static int atm_aal5_connect __P((struct socket *, struct sockaddr *, + struct proc *)); +static int atm_aal5_accept __P((struct socket *, struct sockaddr **)); +static int atm_aal5_disconnect __P((struct socket *)); +static int atm_aal5_shutdown __P((struct socket *)); +static int atm_aal5_send __P((struct socket *, int, KBuffer *, + struct sockaddr *, KBuffer *, struct proc *)); +static int atm_aal5_abort __P((struct socket *)); +static int atm_aal5_control __P((struct socket *, u_long, caddr_t, + struct ifnet *, struct proc *)); +static int atm_aal5_sense __P((struct socket *, struct stat *)); +static int atm_aal5_sockaddr __P((struct socket *, struct sockaddr **)); +static int atm_aal5_peeraddr __P((struct socket *, struct sockaddr **)); +static int atm_aal5_incoming __P((void *, Atm_connection *, + Atm_attributes *, void **)); +static void atm_aal5_cpcs_data __P((void *, KBuffer *)); +static caddr_t atm_aal5_getname __P((void *)); + + +#if (defined(__FreeBSD__) && (BSD >= 199506)) +/* + * New-style socket request routines + */ +struct pr_usrreqs atm_aal5_usrreqs = { + atm_aal5_abort, /* pru_abort */ + atm_aal5_accept, /* pru_accept */ + atm_aal5_attach, /* pru_attach */ + atm_aal5_bind, /* pru_bind */ + atm_aal5_connect, /* pru_connect */ + pru_connect2_notsupp, /* pru_connect2 */ + atm_aal5_control, /* pru_control */ + atm_aal5_detach, /* pru_detach */ + atm_aal5_disconnect, /* pru_disconnect */ + atm_aal5_listen, /* pru_listen */ + atm_aal5_peeraddr, /* pru_peeraddr */ + pru_rcvd_notsupp, /* pru_rcvd */ + pru_rcvoob_notsupp, /* pru_rcvoob */ + atm_aal5_send, /* pru_send */ + atm_aal5_sense, /* pru_sense */ + atm_aal5_shutdown, /* pru_shutdown */ + atm_aal5_sockaddr, /* pru_sockaddr */ + sosend, /* pru_sosend */ + soreceive, /* pru_soreceive */ + sopoll /* pru_sopoll */ +}; +#endif + + +/* + * Local variables + */ +static Atm_endpoint atm_aal5_endpt = { + NULL, + ENDPT_SOCK_AAL5, + NULL, + atm_aal5_getname, + atm_sock_connected, + atm_sock_cleared, + atm_aal5_incoming, + NULL, + NULL, + NULL, + atm_aal5_cpcs_data, + NULL, + NULL, + NULL, + NULL +}; + +static Atm_attributes atm_aal5_defattr = { + NULL, /* nif */ + CMAPI_CPCS, /* api */ + 0, /* api_init */ + 0, /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, + ATM_AAL5 + }, + { /* traffic */ + T_ATM_ABSENT, + }, + { /* bearer */ + T_ATM_ABSENT, + }, + { /* bhli */ + T_ATM_ABSENT + }, + { /* blli */ + T_ATM_ABSENT, + T_ATM_ABSENT, + }, + { /* llc */ + T_ATM_ABSENT, + }, + { /* called */ + T_ATM_ABSENT, + { + T_ATM_ABSENT, + 0 + }, + { + T_ATM_ABSENT, + 0 + } + }, + { /* calling */ + T_ATM_ABSENT + }, + { /* qos */ + T_ATM_ABSENT, + }, + { /* transit */ + T_ATM_ABSENT + }, + { /* cause */ + T_ATM_ABSENT + } +}; + + +/* + * Handy common code macros + */ +#ifdef DIAGNOSTIC +#define ATM_INTRO(f) \ + int s, err = 0; \ + s = splnet(); \ + ATM_DEBUG2("aal5 socket %s (0x%x)\n", f, (int)so); \ + /* \ + * Stack queue should have been drained \ + */ \ + if (atm_stackq_head != NULL) \ + panic("atm_aal5: stack queue not empty"); \ + ; +#else +#define ATM_INTRO(f) \ + int s, err = 0; \ + s = splnet(); \ + ; +#endif + +#define ATM_OUTRO() \ +out: \ + /* \ + * Drain any deferred calls \ + */ \ + STACK_DRAIN(); \ + (void) splx(s); \ + return (err); \ + ; + +#define ATM_RETERR(errno) { \ + err = errno; \ + goto out; \ +} + + +/* + * Attach protocol to socket + * + * Arguments: + * so pointer to socket + * proto protocol identifier + * p pointer to process + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_attach(so, proto, p) + struct socket *so; + int proto; + struct proc *p; +{ + Atm_pcb *atp; + + ATM_INTRO("attach"); + + /* + * Do general attach stuff + */ + err = atm_sock_attach(so, atm_aal5_sendspace, atm_aal5_recvspace); + if (err) + goto out; + + /* + * Finish up any protocol specific stuff + */ + atp = sotoatmpcb(so); + atp->atp_type = ATPT_AAL5; + + /* + * Set default connection attributes + */ + atp->atp_attr = atm_aal5_defattr; + strncpy(atp->atp_name, "(AAL5)", T_ATM_APP_NAME_LEN); + + ATM_OUTRO(); +} + + +/* + * Detach protocol from socket + * + * Arguments: + * so pointer to socket + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_detach(so) + struct socket *so; +{ + ATM_INTRO("detach"); + + err = atm_sock_detach(so); + + ATM_OUTRO(); +} + + +/* + * Bind address to socket + * + * Arguments: + * so pointer to socket + * addr pointer to protocol address + * p pointer to process + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_bind(so, addr, p) + struct socket *so; + struct sockaddr *addr; + struct proc *p; +{ + ATM_INTRO("bind"); + + err = atm_sock_bind(so, addr); + + ATM_OUTRO(); +} + + +/* + * Listen for incoming connections + * + * Arguments: + * so pointer to socket + * p pointer to process + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_listen(so, p) + struct socket *so; + struct proc *p; +{ + ATM_INTRO("listen"); + + err = atm_sock_listen(so, &atm_aal5_endpt); + + ATM_OUTRO(); +} + + +/* + * Connect socket to peer + * + * Arguments: + * so pointer to socket + * addr pointer to protocol address + * p pointer to process + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_connect(so, addr, p) + struct socket *so; + struct sockaddr *addr; + struct proc *p; +{ + Atm_pcb *atp; + + ATM_INTRO("connect"); + + atp = sotoatmpcb(so); + + /* + * Resize send socket buffer to maximum sdu size + */ + if (atp->atp_attr.aal.tag == T_ATM_PRESENT) { + long size; + + size = atp->atp_attr.aal.v.aal5.forward_max_SDU_size; + if (size != T_ATM_ABSENT) + (void) sbreserve(&so->so_snd, size); + } + + /* + * Now get the socket connected + */ + err = atm_sock_connect(so, addr, &atm_aal5_endpt); + + ATM_OUTRO(); +} + + +/* + * Accept pending connection + * + * Arguments: + * so pointer to socket + * addr pointer to pointer to contain protocol address + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_accept(so, addr) + struct socket *so; + struct sockaddr **addr; +{ + ATM_INTRO("accept"); + + /* + * Everything is pretty much done already, we just need to + * return the caller's address to the user. + */ + err = atm_sock_peeraddr(so, addr); + + ATM_OUTRO(); +} + + +/* + * Disconnect connected socket + * + * Arguments: + * so pointer to socket + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_disconnect(so) + struct socket *so; +{ + ATM_INTRO("disconnect"); + + err = atm_sock_disconnect(so); + + ATM_OUTRO(); +} + + +/* + * Shut down socket data transmission + * + * Arguments: + * so pointer to socket + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_shutdown(so) + struct socket *so; +{ + ATM_INTRO("shutdown"); + + socantsendmore(so); + + ATM_OUTRO(); +} + + +/* + * Send user data + * + * Arguments: + * so pointer to socket + * flags send data flags + * m pointer to buffer containing user data + * addr pointer to protocol address + * control pointer to buffer containing protocol control data + * p pointer to process + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_send(so, flags, m, addr, control, p) + struct socket *so; + int flags; + KBuffer *m; + struct sockaddr *addr; + KBuffer *control; + struct proc *p; +{ + Atm_pcb *atp; + + ATM_INTRO("send"); + + /* + * We don't support any control functions + */ + if (control) { + int clen; + + clen = KB_LEN(control); + KB_FREEALL(control); + if (clen) { + KB_FREEALL(m); + ATM_RETERR(EINVAL); + } + } + + /* + * We also don't support any flags or send-level addressing + */ + if (flags || addr) { + KB_FREEALL(m); + ATM_RETERR(EINVAL); + } + + /* + * All we've got left is the data, so push it out + */ + atp = sotoatmpcb(so); + err = atm_cm_cpcs_data(atp->atp_conn, m); + if (err) { + /* + * Output problem, drop packet + */ + atm_sock_stat.as_outdrop[atp->atp_type]++; + KB_FREEALL(m); + } + + ATM_OUTRO(); +} + + +/* + * Abnormally terminate service + * + * Arguments: + * so pointer to socket + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_abort(so) + struct socket *so; +{ + ATM_INTRO("abort"); + + so->so_error = ECONNABORTED; + err = atm_sock_detach(so); + + ATM_OUTRO(); +} + + +/* + * Do control operation - ioctl system call + * + * Arguments: + * so pointer to socket + * cmd ioctl code + * data pointer to code specific parameter data area + * ifp pointer to ifnet structure if it's an interface ioctl + * p pointer to process + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_control(so, cmd, data, ifp, p) + struct socket *so; + u_long cmd; + caddr_t data; + struct ifnet *ifp; + struct proc *p; +{ + ATM_INTRO("control"); + + switch (cmd) { + + default: + err = EOPNOTSUPP; + } + + ATM_OUTRO(); +} + +/* + * Sense socket status - fstat system call + * + * Arguments: + * so pointer to socket + * st pointer to file status structure + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_sense(so, st) + struct socket *so; + struct stat *st; +{ + ATM_INTRO("sense"); + + /* + * Just return the max sdu size for the connection + */ + st->st_blksize = so->so_snd.sb_hiwat; + + ATM_OUTRO(); +} + + +/* + * Retrieve local socket address + * + * Arguments: + * so pointer to socket + * addr pointer to pointer to contain protocol address + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_sockaddr(so, addr) + struct socket *so; + struct sockaddr **addr; +{ + ATM_INTRO("sockaddr"); + + err = atm_sock_sockaddr(so, addr); + + ATM_OUTRO(); +} + + +/* + * Retrieve peer socket address + * + * Arguments: + * so pointer to socket + * addr pointer to pointer to contain protocol address + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_aal5_peeraddr(so, addr) + struct socket *so; + struct sockaddr **addr; +{ + ATM_INTRO("peeraddr"); + + err = atm_sock_peeraddr(so, addr); + + ATM_OUTRO(); +} + + +/* + * Process Incoming Calls + * + * This function will receive control when an incoming call has been matched + * to one of our registered listen parameter blocks. Assuming the call passes + * acceptance criteria and all required resources are available, we will + * create a new protocol control block and socket association. We must + * then await notification of the final SVC setup results. If any + * problems are encountered, we will just tell the connection manager to + * reject the call. + * + * Called at splnet. + * + * Arguments: + * tok owner's matched listening token + * cop pointer to incoming call's connection block + * ap pointer to incoming call's attributes + * tokp pointer to location to store our connection token + * + * Returns: + * 0 call is accepted + * errno call rejected - reason indicated + * + */ +static int +atm_aal5_incoming(tok, cop, ap, tokp) + void *tok; + Atm_connection *cop; + Atm_attributes *ap; + void **tokp; +{ + Atm_pcb *atp = tok; + struct socket *so; + int err = 0; + + /* + * Allocate a new socket and pcb for this connection. + * + * Note that our attach function will be called via sonewconn + * and it will allocate and setup most of the pcb. + */ + atm_sock_stat.as_inconn[atp->atp_type]++; +#if (defined(BSD) && (BSD >= 199103)) + so = sonewconn(atp->atp_socket, 0); +#else + so = sonewconn(atp->atp_socket); +#endif + + if (so) { + /* + * Finish pcb setup and pass pcb back to CM + */ + atp = sotoatmpcb(so); + atp->atp_conn = cop; + *tokp = atp; + } else { + err = ECONNABORTED; + atm_sock_stat.as_connfail[atp->atp_type]++; + } + + return (err); +} + + +/* + * Process Socket VCC Input Data + * + * Arguments: + * tok owner's connection token (atm_pcb) + * m pointer to input packet buffer chain + * + * Returns: + * none + * + */ +static void +atm_aal5_cpcs_data(tok, m) + void *tok; + KBuffer *m; +{ + Atm_pcb *atp = tok; + struct socket *so; + int len; + + so = atp->atp_socket; + + KB_PLENGET(m, len); + + /* + * Ensure that the socket is able to receive data and + * that there's room in the socket buffer + */ + if (((so->so_state & SS_ISCONNECTED) == 0) || + (so->so_state & SS_CANTRCVMORE) || + (len > sbspace(&so->so_rcv))) { + atm_sock_stat.as_indrop[atp->atp_type]++; + KB_FREEALL(m); + return; + } + + /* + * Queue the data and notify the user + */ + sbappendrecord(&so->so_rcv, m); + sorwakeup(so); + + return; +} + + +/* + * Process getsockopt/setsockopt system calls + * + * Arguments: + * so pointer to socket + * sopt pointer to socket option info + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +int +atm_aal5_ctloutput(so, sopt) + struct socket *so; + struct sockopt *sopt; +{ + Atm_pcb *atp; + + ATM_INTRO("ctloutput"); + + /* + * Make sure this is for us + */ + if (sopt->sopt_level != T_ATM_SIGNALING) { + ATM_RETERR(EINVAL); + } + atp = sotoatmpcb(so); + if (atp == NULL) { + ATM_RETERR(ENOTCONN); + } + + switch (sopt->sopt_dir) { + + case SOPT_SET: + /* + * setsockopt() + */ + + /* + * Validate socket state + */ + switch (sopt->sopt_name) { + + case T_ATM_ADD_LEAF: + case T_ATM_DROP_LEAF: + if ((so->so_state & SS_ISCONNECTED) == 0) { + ATM_RETERR(ENOTCONN); + } + break; + + case T_ATM_CAUSE: + break; + + default: + if (so->so_state & SS_ISCONNECTED) { + ATM_RETERR(EISCONN); + } + break; + } + + /* + * Validate and save user-supplied option data + */ + err = atm_sock_setopt(so, sopt, atp); + + break; + + case SOPT_GET: + /* + * getsockopt() + */ + + /* + * Return option data + */ + err = atm_sock_getopt(so, sopt, atp); + + break; + } + + ATM_OUTRO(); +} + + +/* + * Initialize AAL5 Sockets + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +atm_aal5_init() +{ + /* + * Register our endpoint + */ + if (atm_endpoint_register(&atm_aal5_endpt)) + panic("atm_aal5_init: register"); + + /* + * Set default connection attributes + */ + atm_aal5_defattr.aal.v.aal5.forward_max_SDU_size = T_ATM_ABSENT; + atm_aal5_defattr.aal.v.aal5.backward_max_SDU_size = T_ATM_ABSENT; + atm_aal5_defattr.aal.v.aal5.SSCS_type = T_ATM_NULL; +} + + +/* + * Get Connection's Application/Owner Name + * + * Arguments: + * tok owner's connection token (atm_pcb) + * + * Returns: + * addr pointer to string containing our name + * + */ +static caddr_t +atm_aal5_getname(tok) + void *tok; +{ + Atm_pcb *atp = tok; + + return (atp->atp_name); +} + diff --git a/sys/netatm/atm_cm.c b/sys/netatm/atm_cm.c new file mode 100644 index 0000000..55612e3 --- /dev/null +++ b/sys/netatm/atm_cm.c @@ -0,0 +1,3464 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_cm.c,v 1.8 1998/08/06 18:10:42 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * ATM Connection Manager + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_cm.c,v 1.8 1998/08/06 18:10:42 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + + +/* + * Global variables + */ +struct atm_cm_stat atm_cm_stat = {0}; + +/* + * Local functions + */ +static void atm_cm_cpcs_upper __P((int, void *, int, int)); +static void atm_cm_saal_upper __P((int, void *, int, int)); +static void atm_cm_sscop_upper __P((int, void *, int, int)); +static Atm_connvc * atm_cm_share_llc __P((Atm_attributes *)); +static void atm_cm_closeconn __P((Atm_connection *, + struct t_atm_cause *)); +static void atm_cm_closevc __P((Atm_connvc *)); +static void atm_cm_timeout __P((struct atm_time *)); +static KTimeout_ret atm_cm_procinq __P((void *)); +static void atm_cm_incall __P((Atm_connvc *)); +static int atm_cm_accept __P((Atm_connvc *, Atm_connection *)); + +/* + * Local variables + */ +static Queue_t atm_connection_queue = {NULL}; +static Queue_t atm_incoming_queue = {NULL}; +static int atm_incoming_qlen = 0; +static Atm_connection *atm_listen_queue = NULL; +static struct attr_cause atm_cause_tmpl = + {T_ATM_PRESENT, {T_ATM_ITU_CODING, T_ATM_LOC_USER, 0, {0, 0, 0, 0}}}; + +/* + * Stack commands, indexed by API + */ +static struct { + int init; + int term; +} atm_stackcmds[] = { + {CPCS_INIT, CPCS_TERM}, /* CMAPI_CPCS */ + {SSCF_UNI_INIT, SSCF_UNI_TERM}, /* CMAPI_SAAL */ + {SSCOP_INIT, SSCOP_TERM}, /* CMAPI_SSCOP */ +}; + + +static struct sp_info atm_connection_pool = { + "atm connection pool", /* si_name */ + sizeof(Atm_connection), /* si_blksiz */ + 10, /* si_blkcnt */ + 100 /* si_maxallow */ +}; +static struct sp_info atm_connvc_pool = { + "atm connection vcc pool", /* si_name */ + sizeof(Atm_connvc), /* si_blksiz */ + 10, /* si_blkcnt */ + 100 /* si_maxallow */ +}; + + +/* + * Initiate Outgoing ATM Call + * + * Called by an endpoint service to create a new Connection Manager API + * instance and to initiate an outbound ATM connection. The endpoint + * provided token will be used in all further CM -> endpoint function + * calls, and the returned connection block pointer must be used in all + * subsequent endpoint -> CM function calls. + * + * If the return indicates that the connection setup has been immediately + * successful (typically only for PVCs and shared SVCs), then the connection + * is ready for data transmission. + * + * If the return indicates that the connection setup is still in progress, + * then the endpoint must wait for notification from the Connection Manager + * indicating the final status of the call setup. If the call setup completes + * successfully, then a "call connected" notification will be sent to the + * endpoint by the Connection Manager. If the call setup fails, then the + * endpoint will receive a "call cleared" notification. + * + * All connection instances must be freed with an atm_cm_release() call. + * + * Arguments: + * epp pointer to endpoint definition structure + * token endpoint's connection instance token + * ap pointer to requested connection attributes + * copp pointer to location to return allocated connection block + * + * Returns: + * 0 connection has been successfully established + * EINPROGRESS connection establishment is in progress + * errno connection failed - reason indicated + * + */ +int +atm_cm_connect(epp, token, ap, copp) + Atm_endpoint *epp; + void *token; + Atm_attributes *ap; + Atm_connection **copp; +{ + Atm_connection *cop; + Atm_connvc *cvp; + struct atm_pif *pip; + struct sigmgr *smp; + struct stack_list sl; + void (*upf)__P((int, void *, int, int)); + int s, sli, err, err2; + + *copp = NULL; + cvp = NULL; + + /* + * Get a connection block + */ + cop = (Atm_connection *)atm_allocate(&atm_connection_pool); + if (cop == NULL) + return (ENOMEM); + + /* + * Initialize connection info + */ + cop->co_endpt = epp; + cop->co_toku = token; + + /* + * Initialize stack list index + */ + sli = 0; + + /* + * Validate and extract useful attribute information + */ + + /* + * Must specify a network interface (validated below) + */ + if (ap->nif == NULL) { + err = EINVAL; + goto done; + } + + /* + * Check out Data API + */ + switch (ap->api) { + + case CMAPI_CPCS: + upf = atm_cm_cpcs_upper; + break; + + case CMAPI_SAAL: + sl.sl_sap[sli++] = SAP_SSCF_UNI; + sl.sl_sap[sli++] = SAP_SSCOP; + upf = atm_cm_saal_upper; + break; + + case CMAPI_SSCOP: + sl.sl_sap[sli++] = SAP_SSCOP; + upf = atm_cm_sscop_upper; + break; + + default: + err = EINVAL; + goto done; + } + + /* + * AAL Attributes + */ + if (ap->aal.tag != T_ATM_PRESENT) { + err = EINVAL; + goto done; + } + + switch (ap->aal.type) { + + case ATM_AAL5: + sl.sl_sap[sli++] = SAP_CPCS_AAL5; + sl.sl_sap[sli++] = SAP_SAR_AAL5; + sl.sl_sap[sli++] = SAP_ATM; + break; + + case ATM_AAL3_4: + sl.sl_sap[sli++] = SAP_CPCS_AAL3_4; + sl.sl_sap[sli++] = SAP_SAR_AAL3_4; + sl.sl_sap[sli++] = SAP_ATM; + break; + + default: + err = EINVAL; + goto done; + } + + /* + * Broadband Bearer Attributes + */ + if (ap->bearer.tag != T_ATM_PRESENT) { + err = EINVAL; + goto done; + } + + switch (ap->bearer.v.connection_configuration) { + + case T_ATM_1_TO_1: + cop->co_flags |= COF_P2P; + break; + + case T_ATM_1_TO_MANY: + /* Not supported */ + cop->co_flags |= COF_P2MP; + err = EINVAL; + goto done; + + default: + err = EINVAL; + goto done; + } + + /* + * Logical Link Control Attributes + */ + if (ap->llc.tag == T_ATM_PRESENT) { + if ((ap->blli.tag_l2 != T_ATM_PRESENT) || + (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) || + (ap->blli.v.layer_2_protocol.ID.simple_ID != + T_ATM_BLLI2_I8802) || + (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) || + (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) { + err = EINVAL; + goto done; + } + cop->co_mpx = ATM_ENC_LLC; + cop->co_llc = ap->llc; + } else + cop->co_mpx = ATM_ENC_NULL; + + /* + * Called Party Attributes + */ + if (ap->called.tag != T_ATM_PRESENT) { + err = EINVAL; + goto done; + } + + if ((ap->called.addr.address_format == T_ATM_ABSENT) || + (ap->called.addr.address_length == 0)) { + err = EINVAL; + goto done; + } + + /* + * Calling Party Attributes + */ + if (ap->calling.tag != T_ATM_ABSENT) { + err = EINVAL; + goto done; + } + + /* + * Quality of Service Attributes + */ + if (ap->qos.tag != T_ATM_PRESENT) { + err = EINVAL; + goto done; + } + + /* + * Terminate stack list + */ + sl.sl_sap[sli] = 0; + + s = splnet(); + + /* + * Let multiplexors decide whether we need a new VCC + */ + switch (cop->co_mpx) { + + case ATM_ENC_NULL: + /* + * All of these connections require a new VCC + */ + break; + + case ATM_ENC_LLC: + /* + * See if we can share an existing LLC connection + */ + cvp = atm_cm_share_llc(ap); + if (cvp == NULL) + break; + + /* + * We've got a connection to share + */ + cop->co_connvc = cvp; + if (cvp->cvc_state == CVCS_ACTIVE) { + cop->co_state = COS_ACTIVE; + err = 0; + } else { + cop->co_state = COS_OUTCONN; + err = EINPROGRESS; + } + LINK2TAIL(cop, Atm_connection, cvp->cvc_conn->co_mxh, co_next); + cop->co_mxh = cvp->cvc_conn->co_mxh; + *copp = cop; + + (void) splx(s); + return (err); + + default: + panic("atm_cm_connect: unknown mpx"); + } + + /* + * If we get here, it means we need to create + * a new VCC for this connection + */ + + /* + * Validate that network interface is registered and that + * a signalling manager is attached + */ + for (pip = atm_interface_head; pip != NULL; pip = pip->pif_next) { + struct atm_nif *nip; + for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) { + if (nip == ap->nif) + break; + } + if (nip) + break; + } + if (pip == NULL) { + err = ENXIO; + goto donex; + } + + if ((smp = pip->pif_sigmgr) == NULL) { + err = ENXIO; + goto donex; + } + + /* + * Get a connection VCC block + */ + cvp = (Atm_connvc *)atm_allocate(&atm_connvc_pool); + if (cvp == NULL) { + err = ENOMEM; + goto donex; + } + + /* + * Save VCC attributes + */ + cvp->cvc_attr = *ap; + cvp->cvc_flags |= CVCF_CALLER; + + /* + * Link the control blocks + */ + cop->co_connvc = cvp; + cvp->cvc_conn = cop; + cvp->cvc_sigmgr = smp; + + /* + * Create a service stack + */ + err = atm_create_stack(cvp, &sl, upf); + if (err) { + cvp->cvc_state = CVCS_CLEAR; + atm_cm_closevc(cvp); + goto donex; + } + + /* + * Let the signalling manager handle the VCC creation + */ + cvp->cvc_state = CVCS_SETUP; + switch ((*smp->sm_setup)(cvp, &err)) { + + case CALL_CONNECTED: + /* + * Connection is fully setup - initialize the stack + */ + cvp->cvc_state = CVCS_INIT; + STACK_CALL(atm_stackcmds[ap->api].init, cvp->cvc_lower, + cvp->cvc_tokl, cvp, ap->api_init, 0, err2); + if (err2) + panic("atm_cm_connect: init"); + + if (cvp->cvc_flags & CVCF_ABORTING) { + /* + * Someone on the stack bailed out...schedule the + * VCC and stack termination + */ + atm_cm_closevc(cvp); + err = EFAULT; + } else { + /* + * Everything looks fine from here + */ + cvp->cvc_state = CVCS_ACTIVE; + cop->co_state = COS_ACTIVE; + } + break; + + case CALL_FAILED: + /* + * Terminate stack and clean up before we leave + */ + cvp->cvc_state = CVCS_CLEAR; + atm_cm_closevc(cvp); + break; + + case CALL_PROCEEDING: + /* + * We'll just wait for final call status + */ + cop->co_state = COS_OUTCONN; + err = EINPROGRESS; + break; + + default: + panic("atm_cm_connect: setup"); + } + +donex: + (void) splx(s); + +done: + if (err && err != EINPROGRESS) { + /* + * Undo any partial setup stuff + */ + if (cop) + atm_free((caddr_t)cop); + } else { + /* + * Finish connection setup + */ + s = splnet(); + cvp->cvc_flags |= CVCF_CONNQ; + ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue); + LINK2TAIL(cop, Atm_connection, cop->co_mxh, co_next); + (void) splx(s); + *copp = cop; + } + return (err); +} + + +/* + * Listen for Incoming ATM Calls + * + * Called by an endpoint service in order to indicate its willingness to + * accept certain incoming calls. The types of calls which the endpoint + * is prepared to accept are specified in the Atm_attributes parameter. + * + * For each call which meets the criteria specified by the endpoint, the + * endpoint service will receive an incoming call notification via the + * endpoint's ep_incoming() function. + * + * To cancel the listening connection, the endpoint user should invoke + * atm_cm_release(). + * + * Arguments: + * epp pointer to endpoint definition structure + * token endpoint's listen instance token + * ap pointer to listening connection attributes + * copp pointer to location to return allocated connection block + * + * Returns: + * 0 listening connection installed + * errno listen failed - reason indicated + * + */ +int +atm_cm_listen(epp, token, ap, copp) + Atm_endpoint *epp; + void *token; + Atm_attributes *ap; + Atm_connection **copp; +{ + Atm_connection *cop; + int s, err = 0; + + *copp = NULL; + + /* + * Get a connection block + */ + cop = (Atm_connection *)atm_allocate(&atm_connection_pool); + if (cop == NULL) + return (ENOMEM); + + /* + * Initialize connection info + */ + cop->co_endpt = epp; + cop->co_toku = token; + cop->co_mxh = cop; + + /* + * Validate and extract useful attribute information + */ + + /* + * Check out Data API + */ + switch (ap->api) { + + case CMAPI_CPCS: + case CMAPI_SAAL: + case CMAPI_SSCOP: + break; + + default: + err = EINVAL; + goto done; + } + + /* + * AAL Attributes + */ + switch (ap->aal.tag) { + + case T_ATM_PRESENT: + + switch (ap->aal.type) { + + case ATM_AAL5: + case ATM_AAL3_4: + break; + + default: + err = EINVAL; + goto done; + } + break; + + case T_ATM_ABSENT: + case T_ATM_ANY: + break; + + default: + err = EINVAL; + goto done; + } + + /* + * Broadband High Layer Information Attributes + */ + switch (ap->bhli.tag) { + + case T_ATM_PRESENT: + case T_ATM_ABSENT: + case T_ATM_ANY: + break; + + default: + err = EINVAL; + goto done; + } + + /* + * Broadband Low Layer Information Attributes + */ + switch (ap->blli.tag_l2) { + + case T_ATM_PRESENT: + case T_ATM_ABSENT: + case T_ATM_ANY: + break; + + default: + err = EINVAL; + goto done; + } + + switch (ap->blli.tag_l3) { + + case T_ATM_PRESENT: + case T_ATM_ABSENT: + case T_ATM_ANY: + break; + + default: + err = EINVAL; + goto done; + } + + /* + * Logical Link Control Attributes + */ + switch (ap->llc.tag) { + + case T_ATM_PRESENT: + if ((ap->blli.tag_l2 != T_ATM_PRESENT) || + (ap->blli.v.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) || + (ap->blli.v.layer_2_protocol.ID.simple_ID != + T_ATM_BLLI2_I8802) || + (ap->llc.v.llc_len < T_ATM_LLC_MIN_LEN) || + (ap->llc.v.llc_len > T_ATM_LLC_MAX_LEN)) { + err = EINVAL; + goto done; + } + cop->co_mpx = ATM_ENC_LLC; + cop->co_llc = ap->llc; + break; + + case T_ATM_ABSENT: + case T_ATM_ANY: + cop->co_mpx = ATM_ENC_NULL; + break; + + default: + err = EINVAL; + goto done; + } + + /* + * Called Party Attributes + */ + switch (ap->called.tag) { + + case T_ATM_PRESENT: + switch (ap->called.addr.address_format) { + + case T_ATM_ABSENT: + ap->called.tag = T_ATM_ABSENT; + break; + + case T_ATM_PVC_ADDR: + err = EINVAL; + goto done; + } + break; + + case T_ATM_ABSENT: + case T_ATM_ANY: + break; + + default: + err = EINVAL; + goto done; + } + + /* + * Get an attribute block and save listening attributes + */ + cop->co_lattr = (Atm_attributes *)atm_allocate(&atm_attributes_pool); + if (cop->co_lattr == NULL) { + err = ENOMEM; + goto done; + } + *cop->co_lattr = *ap; + + /* + * Now try to register the listening connection + */ + s = splnet(); + if (atm_cm_match(cop->co_lattr, NULL) != NULL) { + /* + * Can't have matching listeners + */ + err = EADDRINUSE; + goto donex; + } + cop->co_state = COS_LISTEN; + LINK2TAIL(cop, Atm_connection, atm_listen_queue, co_next); + +donex: + (void) splx(s); + +done: + if (err) { + /* + * Undo any partial setup stuff + */ + if (cop) { + if (cop->co_lattr) + atm_free((caddr_t)cop->co_lattr); + atm_free((caddr_t)cop); + } + } else { + /* + * Finish connection setup + */ + *copp = cop; + } + return (err); +} + + +/* + * Add to LLC Connection + * + * Called by an endpoint service to create a new Connection Manager API + * instance to be associated with an LLC-multiplexed connection instance + * which has been previously created. The endpoint provided token will + * be used in all further CM -> endpoint function calls, and the returned + * connection block pointer must be used in all subsequent endpoint -> CM + * function calls. + * + * If the return indicates that the connection setup has been immediately + * successful, then the connection is ready for data transmission. + * + * If the return indicates that the connection setup is still in progress, + * then the endpoint must wait for notification from the Connection Manager + * indicating the final status of the call setup. If the call setup completes + * successfully, then a "call connected" notification will be sent to the + * endpoint by the Connection Manager. If the call setup fails, then the + * endpoint will receive a "call cleared" notification. + * + * All connection instances must be freed with an atm_cm_release() call. + * + * Arguments: + * epp pointer to endpoint definition structure + * token endpoint's connection instance token + * llc pointer to llc attributes for new connection + * ecop pointer to existing connection block + * copp pointer to location to return allocated connection block + * + * Returns: + * 0 connection has been successfully established + * EINPROGRESS connection establishment is in progress + * errno addllc failed - reason indicated + * + */ +int +atm_cm_addllc(epp, token, llc, ecop, copp) + Atm_endpoint *epp; + void *token; + struct attr_llc *llc; + Atm_connection *ecop; + Atm_connection **copp; +{ + Atm_connection *cop, *cop2; + Atm_connvc *cvp; + int s, err; + + *copp = NULL; + + /* + * Check out requested LLC attributes + */ + if ((llc->tag != T_ATM_PRESENT) || + ((llc->v.flags & T_ATM_LLC_SHARING) == 0) || + (llc->v.llc_len < T_ATM_LLC_MIN_LEN) || + (llc->v.llc_len > T_ATM_LLC_MAX_LEN)) + return (EINVAL); + + /* + * Get a connection block + */ + cop = (Atm_connection *)atm_allocate(&atm_connection_pool); + if (cop == NULL) + return (ENOMEM); + + /* + * Initialize connection info + */ + cop->co_endpt = epp; + cop->co_toku = token; + cop->co_llc = *llc; + + s = splnet(); + + /* + * Ensure that supplied connection is really valid + */ + cop2 = NULL; + for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp; + cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) { + for (cop2 = cvp->cvc_conn; cop2; cop2 = cop2->co_next) { + if (ecop == cop2) + break; + } + if (cop2) + break; + } + if (cop2 == NULL) { + err = ENOENT; + goto done; + } + + switch (ecop->co_state) { + + case COS_OUTCONN: + case COS_INACCEPT: + err = EINPROGRESS; + break; + + case COS_ACTIVE: + err = 0; + break; + + default: + err = EINVAL; + goto done; + } + + /* + * Connection must be LLC multiplexed and shared + */ + if ((ecop->co_mpx != ATM_ENC_LLC) || + ((ecop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0)) { + err = EINVAL; + goto done; + } + + /* + * This new LLC header must be unique for this VCC + */ + cop2 = ecop->co_mxh; + while (cop2) { + int i = MIN(llc->v.llc_len, cop2->co_llc.v.llc_len); + + if (KM_CMP(llc->v.llc_info, cop2->co_llc.v.llc_info, i) == 0) { + err = EINVAL; + goto done; + } + + cop2 = cop2->co_next; + } + + /* + * Everything seems to check out + */ + cop->co_flags = ecop->co_flags; + cop->co_state = ecop->co_state; + cop->co_mpx = ecop->co_mpx; + cop->co_connvc = ecop->co_connvc; + + LINK2TAIL(cop, Atm_connection, ecop->co_mxh, co_next); + cop->co_mxh = ecop->co_mxh; + +done: + (void) splx(s); + + if (err && err != EINPROGRESS) { + /* + * Undo any partial setup stuff + */ + if (cop) + atm_free((caddr_t)cop); + } else { + /* + * Pass new connection back to caller + */ + *copp = cop; + } + return (err); +} + + +/* + * XXX + * + * Arguments: + * cop pointer to connection block + * id identifier for party to be added + * addr address of party to be added + * + * Returns: + * 0 addparty successful + * errno addparty failed - reason indicated + * + */ +int +atm_cm_addparty(cop, id, addr) + Atm_connection *cop; + int id; + struct t_atm_sap *addr; +{ + return (0); +} + + +/* + * XXX + * + * Arguments: + * cop pointer to connection block + * id identifier for party to be added + * cause pointer to cause of drop + * + * Returns: + * 0 dropparty successful + * errno dropparty failed - reason indicated + * + */ +int +atm_cm_dropparty(cop, id, cause) + Atm_connection *cop; + int id; + struct t_atm_cause *cause; +{ + return (0); +} + + +/* + * Release Connection Resources + * + * Called by the endpoint service in order to terminate an ATM connection + * and to release all system resources for the connection. This function + * must be called for every allocated connection instance and must only + * be called by the connection's owner. + * + * Arguments: + * cop pointer to connection block + * cause pointer to cause of release + * + * Returns: + * 0 release successful + * errno release failed - reason indicated + * + */ +int +atm_cm_release(cop, cause) + Atm_connection *cop; + struct t_atm_cause *cause; +{ + Atm_connvc *cvp; + int s; + + s = splnet(); + + /* + * First, a quick state validation check + */ + switch (cop->co_state) { + + case COS_OUTCONN: + case COS_LISTEN: + case COS_INACCEPT: + case COS_ACTIVE: + case COS_CLEAR: + /* + * Break link to user + */ + cop->co_toku = NULL; + break; + + case COS_INCONN: + (void) splx(s); + return (EFAULT); + + default: + panic("atm_cm_release: bogus conn state"); + } + + /* + * Check out the VCC state too + */ + if (cvp = cop->co_connvc) { + + switch (cvp->cvc_state) { + + case CVCS_SETUP: + case CVCS_INIT: + case CVCS_ACCEPT: + case CVCS_ACTIVE: + break; + + case CVCS_INCOMING: + (void) splx(s); + return (EFAULT); + + case CVCS_CLEAR: + (void) splx(s); + return (EALREADY); + + default: + panic("atm_cm_release: bogus connvc state"); + } + + /* + * If we're the only connection, terminate the VCC + */ + if ((cop->co_mxh == cop) && (cop->co_next == NULL)) { + cvp->cvc_attr.cause.tag = T_ATM_PRESENT; + cvp->cvc_attr.cause.v = *cause; + atm_cm_closevc(cvp); + } + } + + /* + * Now get rid of the connection + */ + atm_cm_closeconn(cop, cause); + + return (0); +} + + +/* + * Abort an ATM Connection VCC + * + * This function allows any non-owner kernel entity to request an + * immediate termination of an ATM VCC. This will normally be called + * when encountering a catastrophic error condition that cannot be + * resolved via the available stack protocols. The connection manager + * will schedule the connection's termination, including notifying the + * connection owner of the termination. + * + * This function should only be called by a stack entity instance. After + * calling the function, the caller should set a protocol state which just + * waits for a <sap>_TERM stack command to be delivered. + * + * Arguments: + * cvp pointer to connection VCC block + * cause pointer to cause of abort + * + * Returns: + * 0 abort successful + * errno abort failed - reason indicated + * + */ +int +atm_cm_abort(cvp, cause) + Atm_connvc *cvp; + struct t_atm_cause *cause; +{ + ATM_DEBUG2("atm_cm_abort: cvp=0x%x cause=%d\n", + (int)cvp, cause->cause_value); + + /* + * Note that we're aborting + */ + cvp->cvc_flags |= CVCF_ABORTING; + + switch (cvp->cvc_state) { + + case CVCS_INIT: + /* + * In-line code will handle this + */ + cvp->cvc_attr.cause.tag = T_ATM_PRESENT; + cvp->cvc_attr.cause.v = *cause; + break; + + case CVCS_SETUP: + case CVCS_ACCEPT: + case CVCS_ACTIVE: + /* + * Schedule connection termination, since we want + * to avoid any sequencing interactions + */ + cvp->cvc_attr.cause.tag = T_ATM_PRESENT; + cvp->cvc_attr.cause.v = *cause; + CVC_TIMER(cvp, 0); + break; + + case CVCS_REJECT: + case CVCS_RELEASE: + case CVCS_CLEAR: + case CVCS_TERM: + /* + * Ignore abort, as we're already terminating + */ + break; + + default: + log(LOG_ERR, + "atm_cm_abort: invalid state: cvp=0x%x, state=%d\n", + (int)cvp, cvp->cvc_state); + } + return (0); +} + + +/* + * Incoming ATM Call Received + * + * Called by a signalling manager to indicate that a new call request has + * been received. This function will allocate and initialize the connection + * manager control blocks and queue this call request. The call request + * processing function, atm_cm_procinq(), will be scheduled to perform the + * call processing. + * + * Arguments: + * vcp pointer to incoming call's VCC control block + * ap pointer to incoming call's attributes + * + * Returns: + * 0 call queuing successful + * errno call queuing failed - reason indicated + * + */ +int +atm_cm_incoming(vcp, ap) + struct vccb *vcp; + Atm_attributes *ap; +{ + Atm_connvc *cvp; + int s, err; + + + /* + * Do some minimal attribute validation + */ + + /* + * Must specify a network interface + */ + if (ap->nif == NULL) + return (EINVAL); + + /* + * AAL Attributes + */ + if ((ap->aal.tag != T_ATM_PRESENT) || + ((ap->aal.type != ATM_AAL5) && + (ap->aal.type != ATM_AAL3_4))) + return (EINVAL); + + /* + * Traffic Descriptor Attributes + */ + if ((ap->traffic.tag != T_ATM_PRESENT) && + (ap->traffic.tag != T_ATM_ABSENT)) + return (EINVAL); + + /* + * Broadband Bearer Attributes + */ + if ((ap->bearer.tag != T_ATM_PRESENT) || + ((ap->bearer.v.connection_configuration != T_ATM_1_TO_1) && + (ap->bearer.v.connection_configuration != T_ATM_1_TO_MANY))) + return (EINVAL); + + /* + * Broadband High Layer Attributes + */ + if ((ap->bhli.tag != T_ATM_PRESENT) && + (ap->bhli.tag != T_ATM_ABSENT)) + return (EINVAL); + + /* + * Broadband Low Layer Attributes + */ + if ((ap->blli.tag_l2 != T_ATM_PRESENT) && + (ap->blli.tag_l2 != T_ATM_ABSENT)) + return (EINVAL); + if ((ap->blli.tag_l3 != T_ATM_PRESENT) && + (ap->blli.tag_l3 != T_ATM_ABSENT)) + return (EINVAL); + + /* + * Logical Link Control Attributes + */ + if (ap->llc.tag == T_ATM_PRESENT) + return (EINVAL); + ap->llc.tag = T_ATM_ANY; + + /* + * Called Party Attributes + */ + if ((ap->called.tag != T_ATM_PRESENT) || + (ap->called.addr.address_format == T_ATM_ABSENT)) + return (EINVAL); + if (ap->called.tag == T_ATM_ABSENT) { + ap->called.addr.address_format = T_ATM_ABSENT; + ap->called.addr.address_length = 0; + ap->called.subaddr.address_format = T_ATM_ABSENT; + ap->called.subaddr.address_length = 0; + } + + /* + * Calling Party Attributes + */ + if ((ap->calling.tag != T_ATM_PRESENT) && + (ap->calling.tag != T_ATM_ABSENT)) + return (EINVAL); + if (ap->calling.tag == T_ATM_ABSENT) { + ap->calling.addr.address_format = T_ATM_ABSENT; + ap->calling.addr.address_length = 0; + ap->calling.subaddr.address_format = T_ATM_ABSENT; + ap->calling.subaddr.address_length = 0; + } + + /* + * Quality of Service Attributes + */ + if (ap->qos.tag != T_ATM_PRESENT) + return (EINVAL); + + /* + * Transit Network Attributes + */ + if ((ap->transit.tag != T_ATM_PRESENT) && + (ap->transit.tag != T_ATM_ABSENT)) + return (EINVAL); + + /* + * Cause Attributes + */ + if ((ap->cause.tag != T_ATM_PRESENT) && + (ap->cause.tag != T_ATM_ABSENT)) + return (EINVAL); + + /* + * Get a connection VCC block + */ + cvp = (Atm_connvc *)atm_allocate(&atm_connvc_pool); + if (cvp == NULL) { + err = ENOMEM; + goto fail; + } + + /* + * Initialize the control block + */ + cvp->cvc_vcc = vcp; + cvp->cvc_sigmgr = vcp->vc_pif->pif_sigmgr; + cvp->cvc_attr = *ap; + cvp->cvc_state = CVCS_INCOMING; + + /* + * Control queue length + */ + s = splnet(); + if (atm_incoming_qlen >= ATM_CALLQ_MAX) { + (void) splx(s); + err = EBUSY; + goto fail; + } + + /* + * Queue request and schedule call processing function + */ + cvp->cvc_flags |= CVCF_INCOMQ; + ENQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue); + if (atm_incoming_qlen++ == 0) { + timeout(atm_cm_procinq, (void *)0, 0); + } + + /* + * Link for signalling manager + */ + vcp->vc_connvc = cvp; + + (void) splx(s); + + return (0); + +fail: + /* + * Free any resources + */ + if (cvp) + atm_free((caddr_t)cvp); + return (err); +} + + +/* + * VCC Connected Notification + * + * This function is called by a signalling manager as notification that a + * VCC call setup has been successful. + * + * Arguments: + * cvp pointer to connection VCC block + * + * Returns: + * none + * + */ +void +atm_cm_connected(cvp) + Atm_connvc *cvp; +{ + Atm_connection *cop, *cop2; + KBuffer *m; + int s, err; + + s = splnet(); + + /* + * Validate connection vcc + */ + switch (cvp->cvc_state) { + + case CVCS_SETUP: + /* + * Initialize the stack + */ + cvp->cvc_state = CVCS_INIT; + STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init, + cvp->cvc_lower, cvp->cvc_tokl, + cvp, cvp->cvc_attr.api_init, 0, err); + if (err) + panic("atm_cm_connected: init"); + + if (cvp->cvc_flags & CVCF_ABORTING) { + /* + * Someone on the stack bailed out...notify all of the + * connections and schedule the VCC termination + */ + cop = cvp->cvc_conn; + while (cop) { + cop2 = cop->co_next; + atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v); + cop = cop2; + } + atm_cm_closevc(cvp); + (void) splx(s); + return; + } + break; + + case CVCS_ACCEPT: + /* + * Stack already initialized + */ + break; + + default: + panic("atm_cm_connected: connvc state"); + } + + /* + * VCC is ready for action + */ + cvp->cvc_state = CVCS_ACTIVE; + + /* + * Notify all connections that the call has completed + */ + cop = cvp->cvc_conn; + while (cop) { + cop2 = cop->co_next; + + switch (cop->co_state) { + + case COS_OUTCONN: + case COS_INACCEPT: + cop->co_state = COS_ACTIVE; + (*cop->co_endpt->ep_connected)(cop->co_toku); + break; + + case COS_ACTIVE: + /* + * May get here if an ep_connected() call (from + * above) results in an atm_cm_addllc() call for + * the just connected connection. + */ + break; + + default: + panic("atm_cm_connected: connection state"); + } + + cop = cop2; + } + + (void) splx(s); + + /* + * Input any queued packets + */ + while (m = cvp->cvc_rcvq) { + cvp->cvc_rcvq = KB_QNEXT(m); + cvp->cvc_rcvqlen--; + KB_QNEXT(m) = NULL; + + /* + * Currently only supported for CPCS API + */ + atm_cm_cpcs_upper(CPCS_UNITDATA_SIG, cvp, (int)m, 0); + } + + return; +} + + +/* + * VCC Cleared Notification + * + * This function is called by a signalling manager as notification that a + * VCC call has been cleared. The cause information describing the reason + * for the call clearing will be contained in the connection VCC attributes. + * + * Arguments: + * cvp pointer to connection VCC block + * + * Returns: + * none + * + */ +void +atm_cm_cleared(cvp) + Atm_connvc *cvp; +{ + Atm_connection *cop, *cop2; + int s; + +#ifdef DIAGNOSTIC + if ((cvp->cvc_state == CVCS_FREE) || + (cvp->cvc_state >= CVCS_CLEAR)) + panic("atm_cm_cleared"); +#endif + + cvp->cvc_state = CVCS_CLEAR; + + s = splnet(); + + /* + * Terminate all connections + */ + cop = cvp->cvc_conn; + while (cop) { + cop2 = cop->co_next; + atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v); + cop = cop2; + } + + /* + * Clean up connection VCC + */ + atm_cm_closevc(cvp); + + (void) splx(s); + + return; +} + + +/* + * Process Incoming Call Queue + * + * This function is scheduled by atm_cm_incoming() in order to process + * all the entries on the incoming call queue. + * + * Arguments: + * arg argument passed on timeout() call + * + * Returns: + * none + * + */ +static KTimeout_ret +atm_cm_procinq(arg) + void *arg; +{ + Atm_connvc *cvp; + int cnt = 0, s; + + /* + * Only process incoming calls up to our quota + */ + while (cnt++ < ATM_CALLQ_MAX) { + + s = splnet(); + + /* + * Get next awaiting call + */ + cvp = Q_HEAD(atm_incoming_queue, Atm_connvc); + if (cvp == NULL) { + (void) splx(s); + break; + } + DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue); + atm_incoming_qlen--; + cvp->cvc_flags &= ~CVCF_INCOMQ; + + /* + * Handle the call + */ + atm_cm_incall(cvp); + + (void) splx(s); + } + + /* + * If we've expended our quota, reschedule ourselves + */ + if (cnt >= ATM_CALLQ_MAX) + timeout(atm_cm_procinq, (void *)0, 0); +} + + +/* + * Process Incoming Call + * + * This function will search through the listening queue and try to find + * matching endpoint(s) for the incoming call. If we find any, we will + * notify the endpoint service(s) of the incoming call and will then + * notify the signalling manager to progress the call to an active status. + * + * If there are no listeners for the call, the signalling manager will be + * notified of a call rejection. + * + * Called at splnet. + * + * Arguments: + * cvp pointer to connection VCC for incoming call + * + * Returns: + * none + * + */ +static void +atm_cm_incall(cvp) + Atm_connvc *cvp; +{ + Atm_connection *cop, *lcop, *hcop; + Atm_attributes attr; + int err; + + hcop = NULL; + lcop = NULL; + cop = NULL; + attr = cvp->cvc_attr; + + /* + * Look for matching listeners + */ + while (lcop = atm_cm_match(&attr, lcop)) { + + if (cop == NULL) { + /* + * Need a new connection block + */ + cop = (Atm_connection *) + atm_allocate(&atm_connection_pool); + if (cop == NULL) { + cvp->cvc_attr.cause = atm_cause_tmpl; + cvp->cvc_attr.cause.v.cause_value = + T_ATM_CAUSE_TEMPORARY_FAILURE; + goto fail; + } + } + + /* + * Initialize connection from listener and incoming call + */ + cop->co_mxh = NULL; + cop->co_state = COS_INCONN; + cop->co_mpx = lcop->co_mpx; + cop->co_endpt = lcop->co_endpt; + cop->co_llc = lcop->co_llc; + + switch (attr.bearer.v.connection_configuration) { + + case T_ATM_1_TO_1: + cop->co_flags |= COF_P2P; + break; + + case T_ATM_1_TO_MANY: + /* Not supported */ + cop->co_flags |= COF_P2MP; + cvp->cvc_attr.cause = atm_cause_tmpl; + cvp->cvc_attr.cause.v.cause_value = + T_ATM_CAUSE_BEARER_CAPABILITY_NOT_IMPLEMENTED; + goto fail; + } + + /* + * Notify endpoint of incoming call + */ + err = (*cop->co_endpt->ep_incoming) + (lcop->co_toku, cop, &cvp->cvc_attr, &cop->co_toku); + + if (err == 0) { + + /* + * Endpoint has accepted the call + * + * Setup call attributes + */ + if (hcop == NULL) { + cvp->cvc_attr.api = lcop->co_lattr->api; + cvp->cvc_attr.api_init = + lcop->co_lattr->api_init; + cvp->cvc_attr.llc = lcop->co_lattr->llc; + } + cvp->cvc_attr.headin = MAX(cvp->cvc_attr.headin, + lcop->co_lattr->headin); + + /* + * Setup connection info and queueing + */ + cop->co_state = COS_INACCEPT; + cop->co_connvc = cvp; + LINK2TAIL(cop, Atm_connection, hcop, co_next); + cop->co_mxh = hcop; + + /* + * Need a new connection block next time around + */ + cop = NULL; + + } else { + /* + * Endpoint refuses call + */ + goto fail; + } + } + + /* + * We're done looking for listeners + */ + if (hcop) { + /* + * Someone actually wants the call, so notify + * the signalling manager to continue + */ + cvp->cvc_flags |= CVCF_CONNQ; + ENQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue); + if (atm_cm_accept(cvp, hcop)) + goto fail; + + } else { + /* + * Nobody around to take the call + */ + cvp->cvc_attr.cause = atm_cause_tmpl; + cvp->cvc_attr.cause.v.cause_value = + T_ATM_CAUSE_INCOMPATIBLE_DESTINATION; + goto fail; + } + + /* + * Clean up loose ends + */ + if (cop) + atm_free((caddr_t)cop); + + /* + * Call has been accepted + */ + return; + +fail: + /* + * Call failed - notify any endpoints of the call failure + */ + + /* + * Clean up loose ends + */ + if (cop) + atm_free((caddr_t)cop); + + if (cvp->cvc_attr.cause.tag != T_ATM_PRESENT) { + cvp->cvc_attr.cause = atm_cause_tmpl; + cvp->cvc_attr.cause.v.cause_value = + T_ATM_CAUSE_UNSPECIFIED_NORMAL; + } + cop = hcop; + while (cop) { + Atm_connection *cop2 = cop->co_next; + atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v); + cop = cop2; + } + + /* + * Tell the signalling manager to reject the call + */ + atm_cm_closevc(cvp); + + return; +} + + +/* + * Accept an Incoming ATM Call + * + * Some endpoint service(s) wants to accept an incoming call, so the + * signalling manager will be notified to attempt to progress the call + * to an active status. + * + * If the signalling manager indicates that connection activation has + * been immediately successful, then all of the endpoints will be notified + * that the connection is ready for data transmission. + * + * If the return indicates that connection activation is still in progress, + * then the endpoints must wait for notification from the Connection Manager + * indicating the final status of the call setup. If the call setup completes + * successfully, then a "call connected" notification will be sent to the + * endpoints by the Connection Manager. If the call setup fails, then the + * endpoints will receive a "call cleared" notification. + * + * Called at splnet. + * + * Arguments: + * cvp pointer to connection VCC for incoming call + * cop pointer to head of accepted connections + * + * Returns: + * 0 connection has been successfully activated + * errno accept failed - reason indicated + * + */ +static int +atm_cm_accept(cvp, cop) + Atm_connvc *cvp; + Atm_connection *cop; +{ + struct stack_list sl; + void (*upf)__P((int, void *, int, int)); + int sli, err, err2; + + + /* + * Link vcc to connections + */ + cvp->cvc_conn = cop; + + /* + * Initialize stack list index + */ + sli = 0; + + /* + * Check out Data API + */ + switch (cvp->cvc_attr.api) { + + case CMAPI_CPCS: + upf = atm_cm_cpcs_upper; + break; + + case CMAPI_SAAL: + sl.sl_sap[sli++] = SAP_SSCF_UNI; + sl.sl_sap[sli++] = SAP_SSCOP; + upf = atm_cm_saal_upper; + break; + + case CMAPI_SSCOP: + sl.sl_sap[sli++] = SAP_SSCOP; + upf = atm_cm_sscop_upper; + break; + + default: + upf = NULL; + } + + /* + * AAL Attributes + */ + switch (cvp->cvc_attr.aal.type) { + + case ATM_AAL5: + sl.sl_sap[sli++] = SAP_CPCS_AAL5; + sl.sl_sap[sli++] = SAP_SAR_AAL5; + sl.sl_sap[sli++] = SAP_ATM; + break; + + case ATM_AAL3_4: + sl.sl_sap[sli++] = SAP_CPCS_AAL3_4; + sl.sl_sap[sli++] = SAP_SAR_AAL3_4; + sl.sl_sap[sli++] = SAP_ATM; + break; + } + + /* + * Terminate stack list + */ + sl.sl_sap[sli] = 0; + + /* + * Create a service stack + */ + err = atm_create_stack(cvp, &sl, upf); + if (err) { + goto done; + } + + /* + * Let the signalling manager finish the VCC activation + */ + switch ((*cvp->cvc_sigmgr->sm_accept)(cvp->cvc_vcc, &err)) { + + case CALL_PROCEEDING: + /* + * Note that we're not finished yet + */ + err = EINPROGRESS; + /* FALLTHRU */ + + case CALL_CONNECTED: + /* + * Initialize the stack now, even if the call isn't totally + * active yet. We want to avoid the delay between getting + * the "call connected" event and actually notifying the + * adapter to accept cells on the new VCC - if the delay is + * too long, then we end up dropping the first pdus sent by + * the caller. + */ + cvp->cvc_state = CVCS_INIT; + STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].init, + cvp->cvc_lower, cvp->cvc_tokl, cvp, + cvp->cvc_attr.api_init, 0, err2); + if (err2) + panic("atm_cm_accept: init"); + + if (cvp->cvc_flags & CVCF_ABORTING) { + /* + * Someone on the stack bailed out...schedule the + * VCC and stack termination + */ + err = ECONNABORTED; + } else { + /* + * Everything looks fine from here + */ + if (err) + cvp->cvc_state = CVCS_ACCEPT; + else + cvp->cvc_state = CVCS_ACTIVE; + } + break; + + case CALL_FAILED: + /* + * Terminate stack and clean up before we leave + */ + cvp->cvc_state = CVCS_CLEAR; + break; + + default: + panic("atm_cm_accept: accept"); + } + +done: + if (err == 0) { + /* + * Call has been connected, notify endpoints + */ + while (cop) { + Atm_connection *cop2 = cop->co_next; + + cop->co_state = COS_ACTIVE; + (*cop->co_endpt->ep_connected)(cop->co_toku); + cop = cop2; + } + + } else if (err == EINPROGRESS) { + /* + * Call is still in progress, endpoint must wait + */ + err = 0; + + } else { + /* + * Let caller know we failed + */ + cvp->cvc_attr.cause = atm_cause_tmpl; + cvp->cvc_attr.cause.v.cause_value = + T_ATM_CAUSE_UNSPECIFIED_RESOURCE_UNAVAILABLE; + } + + return (err); +} + + +/* + * Match Attributes on Listening Queue + * + * This function will attempt to match the supplied connection attributes + * with one of the registered attributes in the listening queue. The pcop + * argument may be supplied in order to allow multiple listeners to share + * an incoming call (if supported by the listeners). + * + * Called at splnet. + * + * Arguments: + * ap pointer to attributes to be matched + * pcop pointer to the previously matched connection + * + * Returns: + * addr connection with which a match was found + * 0 no match found + * + */ +Atm_connection * +atm_cm_match(ap, pcop) + Atm_attributes *ap; + Atm_connection *pcop; +{ + Atm_connection *cop; + Atm_attributes *lap; + + + /* + * If we've already matched a listener... + */ + if (pcop) { + /* + * Make sure already matched listener supports sharing + */ + if ((pcop->co_mpx != ATM_ENC_LLC) || + ((pcop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0)) + return (NULL); + + /* + * Position ourselves after the matched entry + */ + for (cop = atm_listen_queue; cop; cop = cop->co_next) { + if (cop == pcop) { + cop = pcop->co_next; + break; + } + } + } else { + /* + * Start search at top of listening queue + */ + cop = atm_listen_queue; + } + + /* + * Search through listening queue + */ + for (; cop; cop = cop->co_next) { + + lap = cop->co_lattr; + + /* + * If we're trying to share, check that this entry allows it + */ + if (pcop) { + if ((cop->co_mpx != ATM_ENC_LLC) || + ((cop->co_llc.v.flags & T_ATM_LLC_SHARING) == 0)) + continue; + } + + /* + * ALL "matchable" attributes must match + */ + + /* + * BHLI + */ + if (lap->bhli.tag == T_ATM_ABSENT) { + if (ap->bhli.tag == T_ATM_PRESENT) + continue; + } else if (lap->bhli.tag == T_ATM_PRESENT) { + if (ap->bhli.tag == T_ATM_ABSENT) + continue; + if (ap->bhli.tag == T_ATM_PRESENT) + if (KM_CMP(&lap->bhli.v, &ap->bhli.v, + sizeof(struct t_atm_bhli))) + continue; + } + + /* + * BLLI Layer 2 + */ + if (lap->blli.tag_l2 == T_ATM_ABSENT) { + if (ap->blli.tag_l2 == T_ATM_PRESENT) + continue; + } else if (lap->blli.tag_l2 == T_ATM_PRESENT) { + if (ap->blli.tag_l2 == T_ATM_ABSENT) + continue; + if (ap->blli.tag_l2 == T_ATM_PRESENT) { + if (KM_CMP(&lap->blli.v.layer_2_protocol.ID, + &ap->blli.v.layer_2_protocol.ID, + sizeof( + ap->blli.v.layer_2_protocol.ID))) + continue; + } + } + + /* + * BLLI Layer 3 + */ + if (lap->blli.tag_l3 == T_ATM_ABSENT) { + if (ap->blli.tag_l3 == T_ATM_PRESENT) + continue; + } else if (lap->blli.tag_l3 == T_ATM_PRESENT) { + if (ap->blli.tag_l3 == T_ATM_ABSENT) + continue; + if (ap->blli.tag_l3 == T_ATM_PRESENT) { + if (KM_CMP(&lap->blli.v.layer_3_protocol.ID, + &ap->blli.v.layer_3_protocol.ID, + sizeof( + ap->blli.v.layer_3_protocol.ID))) + continue; + } + } + + /* + * LLC + */ + if (lap->llc.tag == T_ATM_ABSENT) { + if (ap->llc.tag == T_ATM_PRESENT) + continue; + } else if (lap->llc.tag == T_ATM_PRESENT) { + if (ap->llc.tag == T_ATM_ABSENT) + continue; + if (ap->llc.tag == T_ATM_PRESENT) { + int i = MIN(lap->llc.v.llc_len, + ap->llc.v.llc_len); + + if (KM_CMP(lap->llc.v.llc_info, + ap->llc.v.llc_info, i)) + continue; + } + } + + /* + * AAL + */ + if (lap->aal.tag == T_ATM_ABSENT) { + if (ap->aal.tag == T_ATM_PRESENT) + continue; + } else if (lap->aal.tag == T_ATM_PRESENT) { + if (ap->aal.tag == T_ATM_ABSENT) + continue; + if (ap->aal.tag == T_ATM_PRESENT) { + if (lap->aal.type != ap->aal.type) + continue; + if (lap->aal.type == ATM_AAL5) { + if (lap->aal.v.aal5.SSCS_type != + ap->aal.v.aal5.SSCS_type) + continue; + } else { + if (lap->aal.v.aal4.SSCS_type != + ap->aal.v.aal4.SSCS_type) + continue; + } + } + } + + /* + * Called Party + */ + if (lap->called.tag == T_ATM_ABSENT) { + if (ap->called.tag == T_ATM_PRESENT) + continue; + } else if (lap->called.tag == T_ATM_PRESENT) { + if (ap->called.tag == T_ATM_ABSENT) + continue; + if (ap->called.tag == T_ATM_PRESENT) { + if ((!ATM_ADDR_EQUAL(&lap->called.addr, + &ap->called.addr)) || + (!ATM_ADDR_EQUAL(&lap->called.subaddr, + &ap->called.subaddr))) + continue; + } + } + + /* + * Found a full match - return it + */ + break; + } + + return (cop); +} + + +/* + * Find Shareable LLC VCC + * + * Given a endpoint-supplied connection attribute using LLC multiplexing, + * this function will attempt to locate an existing connection which meets + * the requirements of the supplied attributes. + * + * Called at splnet. + * + * Arguments: + * ap pointer to requested attributes + * + * Returns: + * addr shareable LLC connection VCC + * 0 no shareable VCC available + * + */ +static Atm_connvc * +atm_cm_share_llc(ap) + Atm_attributes *ap; +{ + Atm_connection *cop; + Atm_connvc *cvp; + + /* + * Is requestor willing to share? + */ + if ((ap->llc.v.flags & T_ATM_LLC_SHARING) == 0) + return (NULL); + + /* + * Try to find a shareable connection + */ + for (cvp = Q_HEAD(atm_connection_queue, Atm_connvc); cvp; + cvp = Q_NEXT(cvp, Atm_connvc, cvc_q)) { + + /* + * Dont use terminating connections + */ + switch (cvp->cvc_state) { + + case CVCS_SETUP: + case CVCS_ACCEPT: + case CVCS_ACTIVE: + break; + + default: + continue; + } + + /* + * Is connection LLC and shareable? + */ + if ((cvp->cvc_attr.llc.tag != T_ATM_PRESENT) || + ((cvp->cvc_attr.llc.v.flags & T_ATM_LLC_SHARING) == 0)) + continue; + + /* + * Match requested attributes with existing connection + */ + if (ap->nif != cvp->cvc_attr.nif) + continue; + + if ((ap->api != cvp->cvc_attr.api) || + (ap->api_init != cvp->cvc_attr.api_init)) + continue; + + /* + * Remote Party + */ + if (cvp->cvc_flags & CVCF_CALLER) { + if ((!ATM_ADDR_EQUAL(&ap->called.addr, + &cvp->cvc_attr.called.addr)) || + (!ATM_ADDR_EQUAL(&ap->called.subaddr, + &cvp->cvc_attr.called.subaddr))) + continue; + } else { + if (cvp->cvc_attr.calling.tag != T_ATM_PRESENT) + continue; + if ((!ATM_ADDR_EQUAL(&ap->called.addr, + &cvp->cvc_attr.calling.addr)) || + (!ATM_ADDR_EQUAL(&ap->called.subaddr, + &cvp->cvc_attr.calling.subaddr))) + continue; + } + + /* + * AAL + */ + if (ap->aal.type = ATM_AAL5) { + struct t_atm_aal5 *ap5, *cv5; + + ap5 = &ap->aal.v.aal5; + cv5 = &cvp->cvc_attr.aal.v.aal5; + + if ((cvp->cvc_attr.aal.type != ATM_AAL5) || + (ap5->SSCS_type != cv5->SSCS_type)) + continue; + + if (cvp->cvc_flags & CVCF_CALLER) { + if (ap5->forward_max_SDU_size > + cv5->forward_max_SDU_size) + continue; + } else { + if (ap5->forward_max_SDU_size > + cv5->backward_max_SDU_size) + continue; + } + } else { + struct t_atm_aal4 *ap4, *cv4; + + ap4 = &ap->aal.v.aal4; + cv4 = &cvp->cvc_attr.aal.v.aal4; + + if ((cvp->cvc_attr.aal.type != ATM_AAL3_4) || + (ap4->SSCS_type != cv4->SSCS_type)) + continue; + + if (cvp->cvc_flags & CVCF_CALLER) { + if (ap4->forward_max_SDU_size > + cv4->forward_max_SDU_size) + continue; + } else { + if (ap4->forward_max_SDU_size > + cv4->backward_max_SDU_size) + continue; + } + } + + /* + * Traffic Descriptor + */ + if ((ap->traffic.tag != T_ATM_PRESENT) || + (cvp->cvc_attr.traffic.tag != T_ATM_PRESENT) || + (ap->traffic.v.best_effort != T_YES) || + (cvp->cvc_attr.traffic.v.best_effort != T_YES)) + continue; + + /* + * Broadband Bearer + */ + if (ap->bearer.v.connection_configuration != + cvp->cvc_attr.bearer.v.connection_configuration) + continue; + + /* + * QOS + */ + if (cvp->cvc_flags & CVCF_CALLER) { + if ((ap->qos.v.forward.qos_class != + cvp->cvc_attr.qos.v.forward.qos_class) || + (ap->qos.v.backward.qos_class != + cvp->cvc_attr.qos.v.backward.qos_class)) + continue; + } else { + if ((ap->qos.v.forward.qos_class != + cvp->cvc_attr.qos.v.backward.qos_class) || + (ap->qos.v.backward.qos_class != + cvp->cvc_attr.qos.v.forward.qos_class)) + continue; + } + + /* + * The new LLC header must also be unique for this VCC + */ + for (cop = cvp->cvc_conn; cop; cop = cop->co_next) { + int i = MIN(ap->llc.v.llc_len, + cop->co_llc.v.llc_len); + + if (KM_CMP(ap->llc.v.llc_info, + cop->co_llc.v.llc_info, i) == 0) + break; + } + + /* + * If no header overlaps, then we're done + */ + if (cop == NULL) + break; + } + + return (cvp); +} + + +/* + * Close Connection + * + * This function will terminate a connection, including notifying the + * user, if necessary, and freeing up control block memory. The caller + * is responsible for managing the connection VCC. + * + * Called at splnet. + * + * Arguments: + * cop pointer to connection block + * cause pointer to cause of close + * + * Returns: + * none + * + */ +static void +atm_cm_closeconn(cop, cause) + Atm_connection *cop; + struct t_atm_cause *cause; +{ + + /* + * Decide whether user needs notification + */ + switch (cop->co_state) { + + case COS_OUTCONN: + case COS_LISTEN: + case COS_INCONN: + case COS_INACCEPT: + case COS_ACTIVE: + /* + * Yup, let 'em know connection is gone + */ + if (cop->co_toku) + (*cop->co_endpt->ep_cleared)(cop->co_toku, cause); + break; + + case COS_CLEAR: + /* + * Nope,they should know already + */ + break; + + default: + panic("atm_cm_closeconn: bogus state"); + } + + /* + * Unlink connection from its queues + */ + switch (cop->co_state) { + + case COS_LISTEN: + atm_free((caddr_t)cop->co_lattr); + UNLINK(cop, Atm_connection, atm_listen_queue, co_next); + break; + + default: + /* + * Remove connection from multiplexor queue + */ + if (cop->co_mxh != cop) { + /* + * Connection is down the chain, just unlink it + */ + UNLINK(cop, Atm_connection, cop->co_mxh, co_next); + + } else if (cop->co_next != NULL) { + /* + * Connection is at the head of a non-singleton chain, + * so unlink and reset the chain head + */ + Atm_connection *t, *nhd; + + t = nhd = cop->co_next; + while (t) { + t->co_mxh = nhd; + t = t->co_next; + } + if (nhd->co_connvc) + nhd->co_connvc->cvc_conn = nhd; + } + } + + /* + * Free the connection block + */ + cop->co_state = COS_FREE; + atm_free((caddr_t)cop); + + return; +} + + +/* + * Close Connection VCC + * + * This function will terminate a connection VCC, including releasing the + * the call to the signalling manager, terminating the VCC protocol stack, + * and freeing up control block memory. + * + * Called at splnet. + * + * Arguments: + * cvp pointer to connection VCC block + * + * Returns: + * none + * + */ +static void +atm_cm_closevc(cvp) + Atm_connvc *cvp; +{ + int err; + + /* + * Break links with the connection block + */ + cvp->cvc_conn = NULL; + + /* + * Cancel any running timer + */ + CVC_CANCEL(cvp); + + /* + * Free queued packets + */ + while (cvp->cvc_rcvq) { + KBuffer *m; + + m = cvp->cvc_rcvq; + cvp->cvc_rcvq = KB_QNEXT(m); + KB_QNEXT(m) = NULL; + KB_FREEALL(m); + } + + /* + * Unlink from any queues + */ + if (cvp->cvc_flags & CVCF_INCOMQ) { + DEQUEUE(cvp, Atm_connvc, cvc_q, atm_incoming_queue); + atm_incoming_qlen--; + cvp->cvc_flags &= ~CVCF_INCOMQ; + + } else if (cvp->cvc_flags & CVCF_CONNQ) { + DEQUEUE(cvp, Atm_connvc, cvc_q, atm_connection_queue); + cvp->cvc_flags &= ~CVCF_CONNQ; + } + + /* + * Release the signalling call + */ + switch (cvp->cvc_state) { + + case CVCS_SETUP: + case CVCS_INIT: + case CVCS_ACCEPT: + case CVCS_ACTIVE: + case CVCS_RELEASE: + if (cvp->cvc_vcc) { + cvp->cvc_state = CVCS_RELEASE; + switch ((*cvp->cvc_sigmgr->sm_release) + (cvp->cvc_vcc, &err)) { + + case CALL_CLEARED: + /* + * Looks good so far... + */ + break; + + case CALL_PROCEEDING: + /* + * We'll have to wait for the call to clear + */ + return; + + case CALL_FAILED: + /* + * If there's a memory shortage, retry later. + * Otherwise who knows what's going on.... + */ + if ((err == ENOMEM) || (err == ENOBUFS)) { + CVC_TIMER(cvp, 1 * ATM_HZ); + return; + } + log(LOG_ERR, + "atm_cm_closevc: release %d\n", err); + break; + } + } + break; + + case CVCS_INCOMING: + case CVCS_REJECT: + if (cvp->cvc_vcc) { + cvp->cvc_state = CVCS_REJECT; + switch ((*cvp->cvc_sigmgr->sm_reject) + (cvp->cvc_vcc, &err)) { + + case CALL_CLEARED: + /* + * Looks good so far... + */ + break; + + case CALL_FAILED: + /* + * If there's a memory shortage, retry later. + * Otherwise who knows what's going on.... + */ + if ((err == ENOMEM) || (err == ENOBUFS)) { + CVC_TIMER(cvp, 1 * ATM_HZ); + return; + } + log(LOG_ERR, + "atm_cm_closevc: reject %d\n", err); + break; + } + } + break; + + case CVCS_CLEAR: + case CVCS_TERM: + /* + * No need for anything here + */ + break; + + default: + panic("atm_cm_closevc: bogus state"); + } + + /* + * Now terminate the stack + */ + if (cvp->cvc_tokl) { + cvp->cvc_state = CVCS_TERM; + + /* + * Wait until stack is unwound before terminating + */ + if ((cvp->cvc_downcnt > 0) || (cvp->cvc_upcnt > 0)) { + CVC_TIMER(cvp, 0); + return; + } + + STACK_CALL(atm_stackcmds[cvp->cvc_attr.api].term, + cvp->cvc_lower, cvp->cvc_tokl, cvp, 0, 0, err); + + cvp->cvc_tokl = NULL; + } + + /* + * Let signalling manager finish up + */ + cvp->cvc_state = CVCS_FREE; + if (cvp->cvc_vcc) { + (void) (*cvp->cvc_sigmgr->sm_free)(cvp->cvc_vcc); + } + + /* + * Finally, free our own control blocks + */ + atm_free((caddr_t)cvp); + + return; +} + + +/* + * Process a Connection VCC timeout + * + * Called when a previously scheduled cvc control block timer expires. + * Processing will be based on the current cvc state. + * + * Called at splnet. + * + * Arguments: + * tip pointer to cvc timer control block + * + * Returns: + * none + * + */ +static void +atm_cm_timeout(tip) + struct atm_time *tip; +{ + Atm_connection *cop, *cop2; + Atm_connvc *cvp; + + /* + * Back-off to cvc control block + */ + cvp = (Atm_connvc *) + ((caddr_t)tip - (int)(&((Atm_connvc *)0)->cvc_time)); + + /* + * Process timeout based on protocol state + */ + switch (cvp->cvc_state) { + + case CVCS_SETUP: + case CVCS_ACCEPT: + case CVCS_ACTIVE: + /* + * Handle VCC abort + */ + if ((cvp->cvc_flags & CVCF_ABORTING) == 0) + goto logerr; + + /* + * Terminate all connections + */ + cop = cvp->cvc_conn; + while (cop) { + cop2 = cop->co_next; + atm_cm_closeconn(cop, &cvp->cvc_attr.cause.v); + cop = cop2; + } + + /* + * Terminate VCC + */ + atm_cm_closevc(cvp); + + break; + + case CVCS_REJECT: + case CVCS_RELEASE: + case CVCS_TERM: + /* + * Retry failed operation + */ + atm_cm_closevc(cvp); + break; + + default: +logerr: + log(LOG_ERR, + "atm_cm_timeout: invalid state: cvp=0x%x, state=%d\n", + (int)cvp, cvp->cvc_state); + } +} + + +/* + * CPCS User Control Commands + * + * This function is called by an endpoint user to pass a control command + * across a CPCS data API. Mostly we just send these down the stack. + * + * Arguments: + * cmd stack command code + * cop pointer to connection block + * arg argument + * + * Returns: + * 0 command output successful + * errno output failed - reason indicated + * + */ +int +atm_cm_cpcs_ctl(cmd, cop, arg) + int cmd; + Atm_connection *cop; + void *arg; +{ + Atm_connvc *cvp; + int err = 0; + + /* + * Validate connection state + */ + if (cop->co_state != COS_ACTIVE) { + err = EFAULT; + goto done; + } + + cvp = cop->co_connvc; + if (cvp->cvc_state != CVCS_ACTIVE) { + err = EFAULT; + goto done; + } + + if (cvp->cvc_attr.api != CMAPI_CPCS) { + err = EFAULT; + goto done; + } + + switch (cmd) { + + default: + err = EINVAL; + } + +done: + return (err); +} + + +/* + * CPCS Data Output + * + * This function is called by an endpoint user to output a data packet + * across a CPCS data API. After we've validated the connection state, the + * packet will be encapsulated (if necessary) and sent down the data stack. + * + * Arguments: + * cop pointer to connection block + * m pointer to packet buffer chain to be output + * + * Returns: + * 0 packet output successful + * errno output failed - reason indicated + * + */ +int +atm_cm_cpcs_data(cop, m) + Atm_connection *cop; + KBuffer *m; +{ + Atm_connvc *cvp; + struct attr_llc *llcp; + int err, space; + void *bp; + + + /* + * Validate connection state + */ + if (cop->co_state != COS_ACTIVE) { + err = EFAULT; + goto done; + } + + cvp = cop->co_connvc; + if (cvp->cvc_state != CVCS_ACTIVE) { + err = EFAULT; + goto done; + } + + if (cvp->cvc_attr.api != CMAPI_CPCS) { + err = EFAULT; + goto done; + } + + /* + * Add any packet encapsulation + */ + switch (cop->co_mpx) { + + case ATM_ENC_NULL: + /* + * None needed... + */ + break; + + case ATM_ENC_LLC: + /* + * Need to add an LLC header + */ + llcp = &cop->co_llc; + + /* + * See if there's room to add LLC header to front of packet. + */ + KB_HEADROOM(m, space); + if (space < llcp->v.llc_len) { + KBuffer *n; + + /* + * We have to allocate another buffer and tack it + * onto the front of the packet + */ + KB_ALLOCPKT(n, llcp->v.llc_len, KB_F_NOWAIT, + KB_T_HEADER); + if (n == 0) { + err = ENOMEM; + goto done; + } + KB_TAILALIGN(n, llcp->v.llc_len); + KB_LINKHEAD(n, m); + m = n; + } else { + /* + * Header fits, just adjust buffer controls + */ + KB_HEADADJ(m, llcp->v.llc_len); + } + + /* + * Add the LLC header + */ + KB_DATASTART(m, bp, void *); + KM_COPY(llcp->v.llc_info, bp, llcp->v.llc_len); + KB_PLENADJ(m, llcp->v.llc_len); + break; + + default: + panic("atm_cm_cpcs_data: mpx"); + } + + /* + * Finally, we can send the packet on its way + */ + STACK_CALL(CPCS_UNITDATA_INV, cvp->cvc_lower, cvp->cvc_tokl, + cvp, (int)m, 0, err); + +done: + return (err); +} + + +/* + * Process CPCS Stack Commands + * + * This is the top of the CPCS API data stack. All upward stack commands + * for the CPCS data API will be received and processed here. + * + * Arguments: + * cmd stack command code + * tok session token (pointer to connection VCC control block) + * arg1 argument 1 + * arg2 argument 2 + * + * Returns: + * none + * + */ +static void +atm_cm_cpcs_upper(cmd, tok, arg1, arg2) + int cmd; + void *tok; + int arg1; + int arg2; +{ + Atm_connection *cop; + Atm_connvc *cvp = tok; + KBuffer *m; + void *bp; + int s; + + switch (cmd) { + + case CPCS_UNITDATA_SIG: + /* + * Input data packet + */ + m = (KBuffer *)arg1; + + if (cvp->cvc_state != CVCS_ACTIVE) { + if (cvp->cvc_state == CVCS_ACCEPT) { + KBuffer *n; + + /* + * Queue up any packets received before sigmgr + * notifies us of incoming call completion + */ + if (cvp->cvc_rcvqlen >= CVC_RCVQ_MAX) { + KB_FREEALL(m); + atm_cm_stat.cms_rcvconnvc++; + return; + } + KB_QNEXT(m) = NULL; + if (cvp->cvc_rcvq == NULL) { + cvp->cvc_rcvq = m; + } else { + for (n = cvp->cvc_rcvq; + KB_QNEXT(n) != NULL; + n = KB_QNEXT(n)) + ; + KB_QNEXT(n) = m; + } + cvp->cvc_rcvqlen++; + return; + } else { + KB_FREEALL(m); + atm_cm_stat.cms_rcvconnvc++; + return; + } + } + + /* + * Locate packet's connection + */ + cop = cvp->cvc_conn; + switch (cop->co_mpx) { + + case ATM_ENC_NULL: + /* + * We're already there... + */ + break; + + case ATM_ENC_LLC: + /* + * Find connection with matching LLC header + */ + if (KB_LEN(m) < T_ATM_LLC_MAX_LEN) { + KB_PULLUP(m, T_ATM_LLC_MAX_LEN, m); + if (m == 0) { + atm_cm_stat.cms_llcdrop++; + return; + } + } + KB_DATASTART(m, bp, void *); + + s = splnet(); + + while (cop) { + if (KM_CMP(bp, cop->co_llc.v.llc_info, + cop->co_llc.v.llc_len) == 0) + break; + cop = cop->co_next; + } + + (void) splx(s); + + if (cop == NULL) { + /* + * No connected user for this LLC + */ + KB_FREEALL(m); + atm_cm_stat.cms_llcid++; + return; + } + + /* + * Strip off the LLC header + */ + KB_HEADADJ(m, -cop->co_llc.v.llc_len); + KB_PLENADJ(m, -cop->co_llc.v.llc_len); + break; + + default: + panic("atm_cm_cpcs_upper: mpx"); + } + + /* + * We've found our connection, so hand the packet off + */ + if (cop->co_state != COS_ACTIVE) { + KB_FREEALL(m); + atm_cm_stat.cms_rcvconn++; + return; + } + (*cop->co_endpt->ep_cpcs_data)(cop->co_toku, m); + break; + + case CPCS_UABORT_SIG: + case CPCS_PABORT_SIG: + /* + * We don't support these (yet), so just fall thru... + */ + + default: + log(LOG_ERR, "atm_cm_cpcs_upper: unknown cmd 0x%x\n", cmd); + } +} + + +/* + * SAAL User Control Commands + * + * This function is called by an endpoint user to pass a control command + * across a SAAL data API. Mostly we just send these down the stack. + * + * Arguments: + * cmd stack command code + * cop pointer to connection block + * arg argument + * + * Returns: + * 0 command output successful + * errno output failed - reason indicated + * + */ +int +atm_cm_saal_ctl(cmd, cop, arg) + int cmd; + Atm_connection *cop; + void *arg; +{ + Atm_connvc *cvp; + int err = 0; + + /* + * Validate connection state + */ + if (cop->co_state != COS_ACTIVE) { + err = EFAULT; + goto done; + } + + cvp = cop->co_connvc; + if (cvp->cvc_state != CVCS_ACTIVE) { + err = EFAULT; + goto done; + } + + if (cvp->cvc_attr.api != CMAPI_SAAL) { + err = EFAULT; + goto done; + } + + switch (cmd) { + + case SSCF_UNI_ESTABLISH_REQ: + case SSCF_UNI_RELEASE_REQ: + /* + * Pass command down the stack + */ + STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp, + (int)arg, 0, err); + break; + + default: + err = EINVAL; + } + +done: + return (err); +} + + +/* + * SAAL Data Output + * + * This function is called by an endpoint user to output a data packet + * across a SAAL data API. After we've validated the connection state, + * the packet will be sent down the data stack. + * + * Arguments: + * cop pointer to connection block + * m pointer to packet buffer chain to be output + * + * Returns: + * 0 packet output successful + * errno output failed - reason indicated + * + */ +int +atm_cm_saal_data(cop, m) + Atm_connection *cop; + KBuffer *m; +{ + Atm_connvc *cvp; + int err; + + + /* + * Validate connection state + */ + if (cop->co_state != COS_ACTIVE) { + err = EFAULT; + goto done; + } + + cvp = cop->co_connvc; + if (cvp->cvc_state != CVCS_ACTIVE) { + err = EFAULT; + goto done; + } + + if (cvp->cvc_attr.api != CMAPI_SAAL) { + err = EFAULT; + goto done; + } + + /* + * Finally, we can send the packet on its way + */ + STACK_CALL(SSCF_UNI_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl, + cvp, (int)m, 0, err); + +done: + return (err); +} + + +/* + * Process SAAL Stack Commands + * + * This is the top of the SAAL API data stack. All upward stack commands + * for the SAAL data API will be received and processed here. + * + * Arguments: + * cmd stack command code + * tok session token (pointer to connection VCC control block) + * arg1 argument 1 + * arg2 argument 2 + * + * Returns: + * none + * + */ +static void +atm_cm_saal_upper(cmd, tok, arg1, arg2) + int cmd; + void *tok; + int arg1; + int arg2; +{ + Atm_connection *cop; + Atm_connvc *cvp = tok; + + + switch (cmd) { + + case SSCF_UNI_ESTABLISH_IND: + case SSCF_UNI_ESTABLISH_CNF: + case SSCF_UNI_RELEASE_IND: + case SSCF_UNI_RELEASE_CNF: + /* + * Control commands + */ + cop = cvp->cvc_conn; + if (cvp->cvc_state != CVCS_ACTIVE) + break; + if (cop->co_state != COS_ACTIVE) + break; + + (*cop->co_endpt->ep_saal_ctl)(cmd, cop->co_toku, (void *)arg1); + break; + + case SSCF_UNI_DATA_IND: + /* + * User data + */ + cop = cvp->cvc_conn; + if (cvp->cvc_state != CVCS_ACTIVE) { + atm_cm_stat.cms_rcvconnvc++; + KB_FREEALL((KBuffer *)arg1); + break; + } + if (cop->co_state != COS_ACTIVE) { + atm_cm_stat.cms_rcvconn++; + KB_FREEALL((KBuffer *)arg1); + break; + } + + (*cop->co_endpt->ep_saal_data)(cop->co_toku, (KBuffer *)arg1); + break; + + case SSCF_UNI_UNITDATA_IND: + /* + * Not supported + */ + KB_FREEALL((KBuffer *)arg1); + + /* FALLTHRU */ + + default: + log(LOG_ERR, "atm_cm_saal_upper: unknown cmd 0x%x\n", cmd); + } +} + + +/* + * SSCOP User Control Commands + * + * This function is called by an endpoint user to pass a control command + * across a SSCOP data API. Mostly we just send these down the stack. + * + * Arguments: + * cmd stack command code + * cop pointer to connection block + * arg1 argument + * arg2 argument + * + * Returns: + * 0 command output successful + * errno output failed - reason indicated + * + */ +int +atm_cm_sscop_ctl(cmd, cop, arg1, arg2) + int cmd; + Atm_connection *cop; + void *arg1; + void *arg2; +{ + Atm_connvc *cvp; + int err = 0; + + /* + * Validate connection state + */ + if (cop->co_state != COS_ACTIVE) { + err = EFAULT; + goto done; + } + + cvp = cop->co_connvc; + if (cvp->cvc_state != CVCS_ACTIVE) { + err = EFAULT; + goto done; + } + + if (cvp->cvc_attr.api != CMAPI_SSCOP) { + err = EFAULT; + goto done; + } + + switch (cmd) { + + case SSCOP_ESTABLISH_REQ: + case SSCOP_ESTABLISH_RSP: + case SSCOP_RELEASE_REQ: + case SSCOP_RESYNC_REQ: + case SSCOP_RESYNC_RSP: + case SSCOP_RECOVER_RSP: + case SSCOP_RETRIEVE_REQ: + /* + * Pass command down the stack + */ + STACK_CALL(cmd, cvp->cvc_lower, cvp->cvc_tokl, cvp, + (int)arg1, (int)arg2, err); + break; + + default: + err = EINVAL; + } + +done: + return (err); +} + + +/* + * SSCOP Data Output + * + * This function is called by an endpoint user to output a data packet + * across a SSCOP data API. After we've validated the connection state, + * the packet will be encapsulated and sent down the data stack. + * + * Arguments: + * cop pointer to connection block + * m pointer to packet buffer chain to be output + * + * Returns: + * 0 packet output successful + * errno output failed - reason indicated + * + */ +int +atm_cm_sscop_data(cop, m) + Atm_connection *cop; + KBuffer *m; +{ + Atm_connvc *cvp; + int err; + + + /* + * Validate connection state + */ + if (cop->co_state != COS_ACTIVE) { + err = EFAULT; + goto done; + } + + cvp = cop->co_connvc; + if (cvp->cvc_state != CVCS_ACTIVE) { + err = EFAULT; + goto done; + } + + if (cvp->cvc_attr.api != CMAPI_SSCOP) { + err = EFAULT; + goto done; + } + + /* + * Finally, we can send the packet on its way + */ + STACK_CALL(SSCOP_DATA_REQ, cvp->cvc_lower, cvp->cvc_tokl, + cvp, (int)m, 0, err); + +done: + return (err); +} + + +/* + * Process SSCOP Stack Commands + * + * This is the top of the SSCOP API data stack. All upward stack commands + * for the SSCOP data API will be received and processed here. + * + * Arguments: + * cmd stack command code + * tok session token (pointer to connection VCC control block) + * arg1 argument 1 + * arg2 argument 2 + * + * Returns: + * none + * + */ +static void +atm_cm_sscop_upper(cmd, tok, arg1, arg2) + int cmd; + void *tok; + int arg1; + int arg2; +{ + Atm_connection *cop; + Atm_connvc *cvp = tok; + + switch (cmd) { + + case SSCOP_ESTABLISH_IND: + case SSCOP_ESTABLISH_CNF: + case SSCOP_RELEASE_IND: + case SSCOP_RESYNC_IND: + /* + * Control commands + */ + cop = cvp->cvc_conn; + if ((cvp->cvc_state != CVCS_ACTIVE) || + (cop->co_state != COS_ACTIVE)) { + KB_FREEALL((KBuffer *)arg1); + break; + } + + (*cop->co_endpt->ep_sscop_ctl) + (cmd, cop->co_toku, (void *)arg1, (void *)arg2); + break; + + case SSCOP_RELEASE_CNF: + case SSCOP_RESYNC_CNF: + case SSCOP_RECOVER_IND: + case SSCOP_RETRIEVE_IND: + case SSCOP_RETRIEVECMP_IND: + /* + * Control commands + */ + cop = cvp->cvc_conn; + if ((cvp->cvc_state != CVCS_ACTIVE) || + (cop->co_state != COS_ACTIVE)) + break; + + (*cop->co_endpt->ep_sscop_ctl) + (cmd, cop->co_toku, (void *)arg1, (void *)arg2); + break; + + case SSCOP_DATA_IND: + /* + * User data + */ + cop = cvp->cvc_conn; + if (cvp->cvc_state != CVCS_ACTIVE) { + atm_cm_stat.cms_rcvconnvc++; + KB_FREEALL((KBuffer *)arg1); + break; + } + if (cop->co_state != COS_ACTIVE) { + atm_cm_stat.cms_rcvconn++; + KB_FREEALL((KBuffer *)arg1); + break; + } + + (*cop->co_endpt->ep_sscop_data) + (cop->co_toku, (KBuffer *)arg1, arg2); + break; + + case SSCOP_UNITDATA_IND: + /* + * Not supported + */ + KB_FREEALL((KBuffer *)arg1); + + /* FALLTHRU */ + + default: + log(LOG_ERR, "atm_cm_sscop_upper: unknown cmd 0x%x\n", cmd); + } +} + + +/* + * Register an ATM Endpoint Service + * + * Every ATM endpoint service must register itself here before it can + * issue or receive any connection requests. + * + * Arguments: + * epp pointer to endpoint definition structure + * + * Returns: + * 0 registration successful + * errno registration failed - reason indicated + * + */ +int +atm_endpoint_register(epp) + Atm_endpoint *epp; +{ + int s = splnet(); + + /* + * See if we need to be initialized + */ + if (!atm_init) + atm_initialize(); + + /* + * Validate endpoint + */ + if (epp->ep_id > ENDPT_MAX) { + (void) splx(s); + return (EINVAL); + } + if (atm_endpoints[epp->ep_id] != NULL) { + (void) splx(s); + return (EEXIST); + } + + /* + * Add endpoint to list + */ + atm_endpoints[epp->ep_id] = epp; + + (void) splx(s); + return (0); +} + + +/* + * De-register an ATM Endpoint Service + * + * Each ATM endpoint service provider must de-register its registered + * endpoint(s) before terminating. Specifically, loaded kernel modules + * must de-register their services before unloading themselves. + * + * Arguments: + * epp pointer to endpoint definition structure + * + * Returns: + * 0 de-registration successful + * errno de-registration failed - reason indicated + * + */ +int +atm_endpoint_deregister(epp) + Atm_endpoint *epp; +{ + int s = splnet(); + + /* + * Validate endpoint + */ + if (epp->ep_id > ENDPT_MAX) { + (void) splx(s); + return (EINVAL); + } + if (atm_endpoints[epp->ep_id] != epp) { + (void) splx(s); + return (ENOENT); + } + + /* + * Remove endpoint from list + */ + atm_endpoints[epp->ep_id] = NULL; + + (void) splx(s); + return (0); +} + diff --git a/sys/netatm/atm_cm.h b/sys/netatm/atm_cm.h new file mode 100644 index 0000000..9e000ab --- /dev/null +++ b/sys/netatm/atm_cm.h @@ -0,0 +1,348 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_cm.h,v 1.3 1998/03/24 20:41:40 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * ATM Connection Management definitions + * + */ + +#ifndef _NETATM_ATM_CM_H +#define _NETATM_ATM_CM_H + +/* + * Forward declaration + */ +struct atm_connection; +struct atm_attributes; + + +#ifdef ATM_KERNEL +/* + * Structure used to define a kernel ATM endpoint service module and its + * associated entry points. An endpoint service is defined as a kernel + * entity which will serve as the endpoint of an ATM connection, i.e. it is + * responsible for issuing/receiving requests to/from the connection manager. + */ +struct atm_endpoint { + struct atm_endpoint *ep_next; /* Next in registry list */ + u_int ep_id; /* Endpoint ID (see below) */ + +/* Exported functions: Miscellaneous */ + int (*ep_ioctl) /* Ioctl */ + __P((int, caddr_t, caddr_t)); + caddr_t (*ep_getname) /* Get application/owner name */ + __P((void *)); + +/* Exported functions: Connection Manager Control API */ + void (*ep_connected) /* Call connected */ + __P((void *)); + void (*ep_cleared) /* Call cleared */ + __P((void *, struct t_atm_cause *)); + int (*ep_incoming) /* Incoming call */ + __P((void *, struct atm_connection *, + struct atm_attributes *, void **)); + int (*ep_addparty) /* Add Party notification */ + __P((void *, int, int)); + int (*ep_dropparty) /* Drop Party notification */ + __P((void *, int, int)); + +/* Exported functions: Connection Manager Data API: CPCS */ + void (*ep_cpcs_ctl) /* Control operation */ + __P((int, void *, void *)); + void (*ep_cpcs_data) /* Received data */ + __P((void *, KBuffer *)); + +/* Exported functions: Connection Manager Data API: SAAL */ + void (*ep_saal_ctl) /* Control operation */ + __P((int, void *, void *)); + void (*ep_saal_data) /* Received data */ + __P((void *, KBuffer *)); + +/* Exported functions: Connection Manager Data API: SSCOP */ + void (*ep_sscop_ctl) /* Control operation */ + __P((int, void *, void *, void *)); + void (*ep_sscop_data) /* Received data */ + __P((void *, KBuffer *, u_int)); +}; +typedef struct atm_endpoint Atm_endpoint; +#endif /* ATM_KERNEL */ + +/* + * Endpoint IDs + */ +#define ENDPT_UNKNOWN 0 /* Unknown */ +#define ENDPT_IP 1 /* IP over ATM */ +#define ENDPT_ATMARP 2 /* ATMARP */ +#define ENDPT_SPANS_SIG 3 /* SPANS Signalling */ +#define ENDPT_SPANS_CLS 4 /* SPANS CLS */ +#define ENDPT_UNI_SIG 5 /* UNI Signalling */ +#define ENDPT_SOCK_AAL5 6 /* Socket - AAL5 */ +#define ENDPT_SOCK_SSCOP 7 /* Socket - SSCOP */ +#define ENDPT_MAX 7 + + +/* + * ATM Connection Attributes + * + * Note: Attribute tag values are the same as the SVE_tag values. + * Unless otherwise specified, attribute field values are the same + * as the corresponding socket option values. + * The above values are all defined in netatm/atm.h. + */ + +/* AAL Attributes */ +struct t_atm_aal4 { + int32_t forward_max_SDU_size; + int32_t backward_max_SDU_size; + int32_t SSCS_type; + int32_t mid_low; + int32_t mid_high; +}; + +struct attr_aal { + int tag; /* Attribute tag */ + Aal_t type; /* AAL type (discriminator) */ + union { + struct t_atm_aal4 aal4; + struct t_atm_aal5 aal5; + } v; /* Attribute value */ +}; + +/* Traffic Descriptor Attributes */ +struct attr_traffic { + int tag; /* Attribute tag */ + struct t_atm_traffic v; /* Attribute value */ +}; + +/* Broadband Bearer Attributes */ +struct attr_bearer { + int tag; /* Attribute tag */ + struct t_atm_bearer v; /* Attribute value */ +}; + +/* Broadband High Layer Information Attributes */ +struct attr_bhli { + int tag; /* Attribute tag */ + struct t_atm_bhli v; /* Attribute value */ +}; + +/* Broadband Low Layer Information Attributes */ +struct attr_blli { + int tag_l2; /* Layer 2 attribute tag */ + int tag_l3; /* Layer 3 attribute tag */ + struct t_atm_blli v; /* Attribute value */ +}; + +/* Logical Link Control Attributes (multiplexing use only, not signalled) */ +struct attr_llc { + int tag; /* Attribute tag */ + struct t_atm_llc v; /* Attribute value */ +}; + +/* Called Party Attributes */ +struct attr_called { + int tag; /* Attribute tag */ + Atm_addr addr; /* Called party address */ + Atm_addr subaddr; /* Called party subaddress */ +}; + +/* Calling Party Attributes */ +struct attr_calling { + int tag; /* Attribute tag */ + Atm_addr addr; /* Calling party address */ + Atm_addr subaddr; /* Calling party subaddress */ + struct t_atm_caller_id cid; /* Caller ID */ +}; + +/* Quality of Service Attributes */ +struct attr_qos { + int tag; /* Attribute tag */ + struct t_atm_qos v; /* Attribute value */ +}; + +/* Transit Network Attributes */ +struct attr_transit { + int tag; /* Attribute tag */ + struct t_atm_transit v; /* Attribute value */ +}; + +/* Cause Attributes */ +struct attr_cause { + int tag; /* Attribute tag */ + struct t_atm_cause v; /* Attribute value */ +}; + + +struct atm_attributes { + struct atm_nif *nif; /* Network interface */ + u_int api; /* Connect Mgr Data API (see below) */ + int api_init;/* API initialization parameter */ + u_short headin; /* Input buffer headroom */ + u_short headout;/* Output buffer headroom */ + struct attr_aal aal; /* AAL attributes */ + struct attr_traffic traffic;/* Traffic descriptor attributes */ + struct attr_bearer bearer; /* Broadband bearer attributes */ + struct attr_bhli bhli; /* Broadband high layer attributes */ + struct attr_blli blli; /* Broadband low layer attributes */ + struct attr_llc llc; /* Logical link control attributes */ + struct attr_called called; /* Called party attributes */ + struct attr_calling calling;/* Calling party attributes */ + struct attr_qos qos; /* Quality of service attributes */ + struct attr_transit transit;/* Transit network attributes */ + struct attr_cause cause; /* Cause attributes */ +}; +typedef struct atm_attributes Atm_attributes; + +/* + * Connection Manager Data APIs + */ +#define CMAPI_CPCS 0 /* AAL CPCS */ +#define CMAPI_SAAL 1 /* Signalling AAL */ +#define CMAPI_SSCOP 2 /* Reliable data (SSCOP) */ + + +#ifdef ATM_KERNEL +/* + * ATM Connection Instance + * + * There will be one connection block for each endpoint <-> Connection Manager + * API instance. Note that with connection multiplexors (e.g. LLC), there + * may be multiple connections per VCC. + */ +struct atm_connection { + struct atm_connection *co_next; /* Multiplexor/listen queue link */ + struct atm_connection *co_mxh; /* Connection multiplexor head */ + u_char co_flags; /* Connection flags (see below) */ + u_char co_state; /* User <-> CM state (see below) */ + Encaps_t co_mpx; /* Multiplexor type */ + void *co_toku; /* Endpoint's session token */ + Atm_endpoint *co_endpt; /* Endpoint service */ + struct atm_connvc *co_connvc; /* Connection VCC */ + struct attr_llc co_llc; /* Connection LLC header */ + Atm_attributes *co_lattr; /* Listening attributes */ +}; +typedef struct atm_connection Atm_connection; + +/* + * Connection Flags + */ +#define COF_P2P 0x01 /* Point-to-point */ +#define COF_P2MP 0x02 /* Point-to-multipoint */ + +/* + * Endpoint <-> Connection Manager States + */ +#define COS_FREE 0 /* Not allocated */ +#define COS_OUTCONN 1 /* Outgoing connection pending */ +#define COS_LISTEN 2 /* Listening for connection */ +#define COS_INCONN 3 /* Incoming connection pending */ +#define COS_INACCEPT 4 /* Incoming connection accepted */ +#define COS_ACTIVE 5 /* Connection active */ +#define COS_CLEAR 6 /* Connection is clearing */ + + +/* + * ATM Connection VCC Instance + * + * There will be one connection-vcc block for each VCC created by the + * Connection Manager. For multiplexed connections, there may be multiple + * connection blocks associated with each connection-vcc. This block is + * used to control the Connection Manager <-> VCC interface, including the + * interfaces to stack management and the signalling manager. + */ +struct atm_connvc { + Qelem_t cvc_q; /* Queueing links */ + Atm_connection *cvc_conn; /* Connection head */ + struct vccb *cvc_vcc; /* VCC for connection */ + struct sigmgr *cvc_sigmgr; /* VCC signalling manager */ + u_char cvc_flags; /* Connection flags (see below) */ + u_char cvc_state; /* CM - VCC state (see below) */ + void *cvc_tokl; /* Stack lower layer token */ + void (*cvc_lower) /* Stack lower layer handler */ + __P((int, void *, int, int)); + u_short cvc_upcnt; /* Up stack calls in progress */ + u_short cvc_downcnt; /* Down stack calls in progress */ + KBuffer *cvc_rcvq; /* Packet receive queue */ + int cvc_rcvqlen; /* Receive queue length */ + Atm_attributes cvc_attr; /* VCC attributes */ + struct atm_time cvc_time; /* Timer controls */ +}; +typedef struct atm_connvc Atm_connvc; + +/* + * Connection Flags + */ +#define CVCF_ABORTING 0x01 /* VCC abort is pending */ +#define CVCF_INCOMQ 0x02 /* VCC is on incoming queue */ +#define CVCF_CONNQ 0x04 /* VCC is on connection queue */ +#define CVCF_CALLER 0x08 /* We are the call originator */ + +/* + * Connection Manager <-> VCC States + */ +#define CVCS_FREE 0 /* Not allocated */ +#define CVCS_SETUP 1 /* Call setup pending */ +#define CVCS_INIT 2 /* Stack INIT pending */ +#define CVCS_INCOMING 3 /* Incoming call present */ +#define CVCS_ACCEPT 4 /* Incoming call accepted */ +#define CVCS_REJECT 5 /* Incoming call rejected */ +#define CVCS_ACTIVE 6 /* Stack active */ +#define CVCS_RELEASE 7 /* Connection release pending */ +#define CVCS_CLEAR 8 /* Call has been cleared */ +#define CVCS_TERM 9 /* Stack TERM pending */ + + +/* + * Connection VCC variables + */ +#define CVC_RCVQ_MAX 3 /* Max length of receive queue */ + + +/* + * Timer macros + */ +#define CVC_TIMER(s, t) atm_timeout(&(s)->cvc_time, (t), atm_cm_timeout) +#define CVC_CANCEL(s) atm_untimeout(&(s)->cvc_time) + + +/* + * Connection Manager Statistics + */ +struct atm_cm_stat { + u_long cms_llcdrop; /* Packets dropped by llc demux'ing */ + u_long cms_llcid; /* Packets with unknown llc id */ + u_long cms_rcvconn; /* Packets dropped, bad conn state */ + u_long cms_rcvconnvc; /* Packets dropped, bad connvc state */ +}; +#endif /* ATM_KERNEL */ + +#endif /* _NETATM_ATM_CM_H */ diff --git a/sys/netatm/atm_device.c b/sys/netatm/atm_device.c new file mode 100644 index 0000000..7f26695 --- /dev/null +++ b/sys/netatm/atm_device.c @@ -0,0 +1,883 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_device.c,v 1.7 1998/03/24 20:42:39 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * ATM device support functions + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_device.c,v 1.7 1998/03/24 20:42:39 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + + +/* + * Private structures for managing allocated kernel memory resources + * + * For each allocation of kernel memory, one Mem_ent will be used. + * The Mem_ent structures will be allocated in blocks inside of a + * Mem_blk structure. + */ +#define MEM_NMEMENT 10 /* How many Mem_ent's in a Mem_blk */ + +struct mem_ent { + void *me_kaddr; /* Allocated memory address */ + u_int me_ksize; /* Allocated memory length */ + void *me_uaddr; /* Memory address returned to caller */ + u_int me_flags; /* Flags (see below) */ +}; +typedef struct mem_ent Mem_ent; + +/* + * Memory entry flags + */ +#define MEF_NONCACHE 1 /* Memory is noncacheable */ + + +struct mem_blk { + struct mem_blk *mb_next; /* Next block in chain */ + Mem_ent mb_mement[MEM_NMEMENT]; /* Allocated memory entries */ +}; +typedef struct mem_blk Mem_blk; + +static Mem_blk *atm_mem_head = NULL; + +static struct t_atm_cause atm_dev_cause = { + T_ATM_ITU_CODING, + T_ATM_LOC_USER, + T_ATM_CAUSE_VPCI_VCI_ASSIGNMENT_FAILURE, + {0, 0, 0, 0} +}; + + +/* + * ATM Device Stack Instantiation + * + * Called at splnet. + * + * Arguments + * ssp pointer to array of stack definition pointers + * for connection + * ssp[0] points to upper layer's stack definition + * ssp[1] points to this layer's stack definition + * ssp[2] points to lower layer's stack definition + * cvcp pointer to connection vcc for this stack + * + * Returns + * 0 instantiation successful + * err instantiation failed - reason indicated + * + */ +int +atm_dev_inst(ssp, cvcp) + struct stack_defn **ssp; + Atm_connvc *cvcp; +{ + Cmn_unit *cup = (Cmn_unit *)cvcp->cvc_attr.nif->nif_pif; + Cmn_vcc *cvp; + int err; + + /* + * Check to see if device has been initialized + */ + if ((cup->cu_flags & CUF_INITED) == 0) + return ( EIO ); + + /* + * Validate lower SAP + */ + /* + * Device driver is the lowest layer - no need to validate + */ + + /* + * Validate PVC vpi.vci + */ + if (cvcp->cvc_attr.called.addr.address_format == T_ATM_PVC_ADDR) { + /* + * Look through existing circuits - return error if found + */ + Atm_addr_pvc *pp; + + pp = (Atm_addr_pvc *)cvcp->cvc_attr.called.addr.address; + if (atm_dev_vcc_find(cup, ATM_PVC_GET_VPI(pp), + ATM_PVC_GET_VCI(pp), 0)) + return ( EADDRINUSE ); + } + + /* + * Validate our SAP type + */ + switch ((*(ssp+1))->sd_sap) { + case SAP_CPCS_AAL3_4: + case SAP_CPCS_AAL5: + case SAP_ATM: + break; + default: + return (EINVAL); + } + + /* + * Allocate a VCC control block + */ + if ( ( cvp = (Cmn_vcc *)atm_allocate(cup->cu_vcc_pool) ) == NULL ) + return ( ENOMEM ); + + cvp->cv_state = CVS_INST; + cvp->cv_toku = (*ssp)->sd_toku; + cvp->cv_upper = (*ssp)->sd_upper; + cvp->cv_connvc = cvcp; + + /* + * Let device have a look at the connection request + */ + err = (*cup->cu_instvcc)(cup, cvp); + if (err) { + atm_free((caddr_t)cvp); + return (err); + } + + /* + * Looks good so far, so link in device VCC + */ + LINK2TAIL ( cvp, Cmn_vcc, cup->cu_vcc, cv_next ); + + /* + * Save my token + */ + (*++ssp)->sd_toku = cvp; + + /* + * Pass instantiation down the stack + */ + /* + * No need - we're the lowest point. + */ + /* err = (*(ssp + 1))->sd_inst(ssp, cvcp); */ + + /* + * Save the lower layer's interface info + */ + /* + * No need - we're the lowest point + */ + /* cvp->cv_lower = (*++ssp)->sd_lower; */ + /* cvp->cv_tok1 = (*ssp)->sd_toku; */ + + return (0); +} + + +/* + * ATM Device Stack Command Handler + * + * Arguments + * cmd stack command code + * tok session token (Cmn_vcc) + * arg1 command specific argument + * arg2 command specific argument + * + * Returns + * none + * + */ +/*ARGSUSED*/ +void +atm_dev_lower(cmd, tok, arg1, arg2) + int cmd; + void *tok; + int arg1; + int arg2; +{ + Cmn_vcc *cvp = (Cmn_vcc *)tok; + Atm_connvc *cvcp = cvp->cv_connvc; + Cmn_unit *cup = (Cmn_unit *)cvcp->cvc_attr.nif->nif_pif; + struct vccb *vcp; + u_int state; + int s; + + switch ( cmd ) { + + case CPCS_INIT: + /* + * Sanity check + */ + if ( cvp->cv_state != CVS_INST ) { + log ( LOG_ERR, + "atm_dev_lower: INIT: tok=0x%x, state=%d\n", + (int)tok, cvp->cv_state ); + break; + } + + vcp = cvp->cv_connvc->cvc_vcc; + + /* + * Validate SVC vpi.vci + */ + if ( vcp->vc_type & VCC_SVC ) { + + if (atm_dev_vcc_find(cup, vcp->vc_vpi, vcp->vc_vci, + vcp->vc_type & (VCC_IN | VCC_OUT)) + != cvp){ + log ( LOG_ERR, + "atm_dev_lower: dup SVC (%d,%d) tok=0x%x\n", + vcp->vc_vpi, vcp->vc_vci, (int)tok ); + atm_cm_abort(cvp->cv_connvc, &atm_dev_cause); + break; + } + } + + /* + * Tell the device to open the VCC + */ + cvp->cv_state = CVS_INITED; + s = splimp(); + if ((*cup->cu_openvcc)(cup, cvp)) { + atm_cm_abort(cvp->cv_connvc, &atm_dev_cause); + (void) splx(s); + break; + } + (void) splx(s); + break; + + case CPCS_TERM: { + KBuffer *m, *prev, *next; + int *ip; + + s = splimp(); + + /* + * Disconnect the VCC - ignore return code + */ + if ((cvp->cv_state == CVS_INITED) || + (cvp->cv_state == CVS_ACTIVE)) { + (void) (*cup->cu_closevcc)(cup, cvp); + } + cvp->cv_state = CVS_TERM; + + /* + * Remove from interface list + */ + UNLINK ( cvp, Cmn_vcc, cup->cu_vcc, cv_next ); + + /* + * Free any buffers from this VCC on the ATM interrupt queue + */ + prev = NULL; + for (m = atm_intrq.ifq_head; m; m = next) { + next = KB_QNEXT(m); + + /* + * See if this entry is for the terminating VCC + */ + KB_DATASTART(m, ip, int *); + ip++; + if (*ip == (int)cvp) { + /* + * Yep, so dequeue the entry + */ + if (prev == NULL) + atm_intrq.ifq_head = next; + else + KB_QNEXT(prev) = next; + + if (next == NULL) + atm_intrq.ifq_tail = prev; + + atm_intrq.ifq_len--; + + /* + * Free the unwanted buffers + */ + KB_FREEALL(m); + } else { + prev = m; + } + } + (void) splx(s); + + /* + * Free VCC resources + */ + (void) atm_free((caddr_t)cvp); + break; + } + + case CPCS_UNITDATA_INV: + + /* + * Sanity check + * + * Use temp state variable since we dont want to lock out + * interrupts, but initial VC activation interrupt may + * happen here, changing state somewhere in the middle. + */ + state = cvp->cv_state; + if ((state != CVS_ACTIVE) && + (state != CVS_INITED)) { + log ( LOG_ERR, + "atm_dev_lower: UNITDATA: tok=0x%x, state=%d\n", + (int)tok, state ); + KB_FREEALL((KBuffer *)arg1); + break; + } + + /* + * Hand the data off to the device + */ + (*cup->cu_output)(cup, cvp, (KBuffer *)arg1); + + break; + + case CPCS_UABORT_INV: + log ( LOG_ERR, + "atm_dev_lower: unimplemented stack cmd 0x%x, tok=0x%x\n", + cmd, (int)tok ); + break; + + default: + log ( LOG_ERR, + "atm_dev_lower: unknown stack cmd 0x%x, tok=0x%x\n", + cmd, (int)tok ); + + } + + return; +} + + + +/* + * Allocate kernel memory block + * + * This function will allocate a kernel memory block of the type specified + * in the flags parameter. The returned address will point to a memory + * block of the requested size and alignment. The memory block will also + * be zeroed. The alloc/free functions will manage/mask both the OS-specific + * kernel memory management requirements and the bookkeeping required to + * deal with data alignment issues. + * + * This function should not be called from interrupt level. + * + * Arguments: + * size size of memory block to allocate + * align data alignment requirement + * flags allocation flags (ATM_DEV_*) + * + * Returns: + * uaddr pointer to aligned memory block + * NULL unable to allocate memory + * + */ +void * +atm_dev_alloc(size, align, flags) + u_int size; + u_int align; + u_int flags; +{ + Mem_blk *mbp; + Mem_ent *mep; + u_int kalign, ksize; + int s, i; + + s = splimp(); + + /* + * Find a free Mem_ent + */ + mep = NULL; + for (mbp = atm_mem_head; mbp && mep == NULL; mbp = mbp->mb_next) { + for (i = 0; i < MEM_NMEMENT; i++) { + if (mbp->mb_mement[i].me_uaddr == NULL) { + mep = &mbp->mb_mement[i]; + break; + } + } + } + + /* + * If there are no free Mem_ent's, then allocate a new Mem_blk + * and link it into the chain + */ + if (mep == NULL) { + mbp = (Mem_blk *) KM_ALLOC(sizeof(Mem_blk), M_DEVBUF, M_NOWAIT); + if (mbp == NULL) { + log(LOG_ERR, "atm_dev_alloc: Mem_blk failure\n"); + (void) splx(s); + return (NULL); + } + KM_ZERO(mbp, sizeof(Mem_blk)); + + mbp->mb_next = atm_mem_head; + atm_mem_head = mbp; + mep = mbp->mb_mement; + } + + /* + * Now we need to get the kernel's allocation alignment minimum + * + * This is obviously very OS-specific stuff + */ +#ifdef sun + if (flags & ATM_DEV_NONCACHE) { + /* Byte-aligned */ + kalign = sizeof(long); + } else { + /* Doubleword-aligned */ + kalign = sizeof(double); + } +#elif (defined(BSD) && (BSD >= 199103)) + kalign = MINALLOCSIZE; +#else + #error Unsupported/unconfigured OS +#endif + + /* + * Figure out how much memory we must allocate to satify the + * user's size and alignment needs + */ + if (align <= kalign) + ksize = size; + else + ksize = size + align - kalign; + + /* + * Finally, go get the memory + */ + if (flags & ATM_DEV_NONCACHE) { +#ifdef sun + mep->me_kaddr = IOPBALLOC(ksize); +#elif defined(__i386__) + mep->me_kaddr = KM_ALLOC(ksize, M_DEVBUF, M_NOWAIT); +#else + #error Unsupported/unconfigured OS +#endif + } else { + mep->me_kaddr = KM_ALLOC(ksize, M_DEVBUF, M_NOWAIT); + } + + if (mep->me_kaddr == NULL) { + log(LOG_ERR, "atm_dev_alloc: %skernel memory unavailable\n", + (flags & ATM_DEV_NONCACHE) ? "non-cacheable " : ""); + (void) splx(s); + return (NULL); + } + + /* + * Calculate correct alignment address to pass back to user + */ + mep->me_uaddr = (void *) roundup((u_int)mep->me_kaddr, align); + mep->me_ksize = ksize; + mep->me_flags = flags; + + /* + * Clear memory for user + */ + KM_ZERO(mep->me_uaddr, size); + + ATM_DEBUG4("atm_dev_alloc: size=%d, align=%d, flags=%d, uaddr=0x%x\n", + size, align, flags, (int)mep->me_uaddr); + + (void) splx(s); + + return (mep->me_uaddr); +} + + +/* + * Free kernel memory block + * + * This function will free a kernel memory block previously allocated by + * the atm_dev_alloc function. + * + * This function should not be called from interrupt level. + * + * Arguments: + * uaddr pointer to allocated aligned memory block + * + * Returns: + * none + * + */ +void +atm_dev_free(uaddr) + void *uaddr; +{ + Mem_blk *mbp; + Mem_ent *mep; + int s, i; + + ATM_DEBUG1("atm_dev_free: uaddr=0x%x\n", (int)uaddr); + + s = splimp(); + + /* + * Protect ourselves... + */ + if (uaddr == NULL) + panic("atm_dev_free: trying to free null address"); + + /* + * Find our associated entry + */ + mep = NULL; + for (mbp = atm_mem_head; mbp && mep == NULL; mbp = mbp->mb_next) { + for (i = 0; i < MEM_NMEMENT; i++) { + if (mbp->mb_mement[i].me_uaddr == uaddr) { + mep = &mbp->mb_mement[i]; + break; + } + } + } + + /* + * If we didn't find our entry, then unceremoniously let the caller + * know they screwed up (it certainly couldn't be a bug here...) + */ + if (mep == NULL) + panic("atm_dev_free: trying to free unknown address"); + + /* + * Give the memory space back to the kernel + */ + if (mep->me_flags & ATM_DEV_NONCACHE) { +#ifdef sun + IOPBFREE(mep->me_kaddr, mep->me_ksize); +#elif defined(__i386__) + KM_FREE(mep->me_kaddr, mep->me_ksize, M_DEVBUF); +#else + #error Unsupported/unconfigured OS +#endif + } else { + KM_FREE(mep->me_kaddr, mep->me_ksize, M_DEVBUF); + } + + /* + * Free our entry + */ + mep->me_uaddr = NULL; + + (void) splx(s); + + return; +} + + +#ifdef sun4m + +typedef int (*func_t)(); + +/* + * Map an address into DVMA space + * + * This function will take a kernel virtual address and map it to + * a DMA virtual address which can be used during SBus DMA cycles. + * + * Arguments: + * addr kernel virtual address + * len length of DVMA space requested + * flags allocation flags (ATM_DEV_*) + * + * Returns: + * a DVMA address + * NULL unable to map into DMA space + * + */ +void * +atm_dma_map(addr, len, flags) + caddr_t addr; + int len; + int flags; +{ + if (flags & ATM_DEV_NONCACHE) + /* + * Non-cacheable memory is already DMA'able + */ + return ((void *)addr); + else + return ((void *)mb_nbmapalloc(bigsbusmap, addr, len, + MDR_BIGSBUS|MB_CANTWAIT, (func_t)NULL, (caddr_t)NULL)); +} + + +/* + * Free a DVMA map address + * + * This function will free DVMA map resources (addresses) previously + * allocated with atm_dma_map(). + * + * Arguments: + * addr DMA virtual address + * flags allocation flags (ATM_DEV_*) + * + * Returns: + * none + * + */ +void +atm_dma_free(addr, flags) + caddr_t addr; + int flags; +{ + if ((flags & ATM_DEV_NONCACHE) == 0) + mb_mapfree(bigsbusmap, (int)&addr); + + return; +} +#endif /* sun4m */ + + +/* + * Compress buffer chain + * + * This function will compress a supplied buffer chain into a minimum number + * of kernel buffers. Typically, this function will be used because the + * number of buffers in an output buffer chain is too large for a device's + * DMA capabilities. This should only be called as a last resort, since + * all the data copying will surely kill any hopes of decent performance. + * + * Arguments: + * m pointer to source buffer chain + * + * Returns: + * n pointer to compressed buffer chain + * + */ +KBuffer * +atm_dev_compress(m) + KBuffer *m; +{ + KBuffer *n, *n0, **np; + int len, space; + caddr_t src, dst; + + n = n0 = NULL; + np = &n0; + dst = NULL; + space = 0; + + /* + * Copy each source buffer into compressed chain + */ + while (m) { + + if (space == 0) { + + /* + * Allocate another buffer for compressed chain + */ + KB_ALLOCEXT(n, ATM_DEV_CMPR_LG, KB_F_NOWAIT, KB_T_DATA); + if (n) { + space = ATM_DEV_CMPR_LG; + } else { + KB_ALLOC(n, ATM_DEV_CMPR_SM, KB_F_NOWAIT, + KB_T_DATA); + if (n) { + space = ATM_DEV_CMPR_SM; + } else { + /* + * Unable to get any new buffers, so + * just return the partially compressed + * chain and hope... + */ + *np = m; + break; + } + } + + KB_HEADSET(n, 0); + KB_LEN(n) = 0; + KB_BFRSTART(n, dst, caddr_t); + + *np = n; + np = &KB_NEXT(n); + } + + /* + * Copy what we can from source buffer + */ + len = MIN(space, KB_LEN(m)); + KB_DATASTART(m, src, caddr_t); + KM_COPY(src, dst, len); + + /* + * Adjust for copied data + */ + dst += len; + space -= len; + + KB_HEADADJ(m, -len); + KB_TAILADJ(n, len); + + /* + * If we've exhausted our current source buffer, free it + * and move to the next one + */ + if (KB_LEN(m) == 0) { + KB_FREEONE(m, m); + } + } + + return (n0); +} + + +/* + * Locate VCC entry + * + * This function will return the VCC entry for a specified interface and + * VPI/VCI value. + * + * Arguments: + * cup pointer to interface unit structure + * vpi VPI value + * vci VCI value + * type VCC type + * + * Returns: + * vcp pointer to located VCC entry matching + * NULL no VCC found + * + */ +Cmn_vcc * +atm_dev_vcc_find(cup, vpi, vci, type) + Cmn_unit *cup; + u_int vpi; + u_int vci; + u_int type; +{ + Cmn_vcc *cvp; + int s = splnet(); + + /* + * Go find VCC + * + * (Probably should stick in a hash table some time) + */ + for (cvp = cup->cu_vcc; cvp; cvp = cvp->cv_next) { + struct vccb *vcp; + + vcp = cvp->cv_connvc->cvc_vcc; + if ((vcp->vc_vci == vci) && (vcp->vc_vpi == vpi) && + ((vcp->vc_type & type) == type)) + break; + } + + (void) splx(s); + return (cvp); +} + + +#ifdef notdef +/* + * Module unloading notification + * + * This function must be called just prior to unloading the module from + * memory. All allocated memory will be freed here and anything else that + * needs cleaning up. + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +atm_unload() +{ + Mem_blk *mbp; + Mem_ent *mep; + int s, i; + + s = splimp(); + + /* + * Free up all of our memory management storage + */ + while (mbp = atm_mem_head) { + + /* + * Make sure users have freed up all of their memory + */ + for (i = 0; i < MEM_NMEMENT; i++) { + if (mbp->mb_mement[i].me_uaddr != NULL) { + panic("atm_unload: unfreed memory"); + } + } + + atm_mem_head = mbp->mb_next; + + /* + * Hand this block back to the kernel + */ + KM_FREE((caddr_t) mbp, sizeof(Mem_blk), M_DEVBUF); + } + + (void) splx(s); + + return; +} +#endif /* notdef */ + + +/* + * Print a PDU + * + * Arguments: + * cup pointer to device unit + * cvp pointer to VCC control block + * m pointer to pdu buffer chain + * msg pointer to message string + * + * Returns: + * none + * + */ +void +atm_dev_pdu_print(cup, cvp, m, msg) + Cmn_unit *cup; + Cmn_vcc *cvp; + KBuffer *m; + char *msg; +{ + char buf[128]; + + sprintf(buf, "%s vcc=(%d,%d)", msg, + cvp->cv_connvc->cvc_vcc->vc_vpi, + cvp->cv_connvc->cvc_vcc->vc_vci); + + atm_pdu_print(m, buf); +} + diff --git a/sys/netatm/atm_if.c b/sys/netatm/atm_if.c new file mode 100644 index 0000000..a07ccc2 --- /dev/null +++ b/sys/netatm/atm_if.c @@ -0,0 +1,1202 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_if.c,v 1.13 1998/07/23 21:43:55 root Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * ATM interface management + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_if.c,v 1.13 1998/07/23 21:43:55 root Exp $"; +#endif + +#include <netatm/kern_include.h> + + +#if (defined(BSD) && (BSD < 199506)) +extern int ifqmaxlen; +#endif + +/* + * Local functions + */ +static int atm_physif_ioctl __P((int, caddr_t, caddr_t)); +#if (defined(BSD) && (BSD >= 199306)) +static int atm_netif_rtdel __P((struct radix_node *, void *)); +#endif +static int atm_if_ioctl __P((struct ifnet *, u_long, caddr_t)); +static int atm_ifparse __P((char *, char *, int, int *)); + +/* + * Local variables + */ +static int (*atm_ifouttbl[AF_MAX+1]) + __P((struct ifnet *, KBuffer *, struct sockaddr *)) + = {NULL}; + + +/* + * Register an ATM physical interface + * + * Each ATM device interface must register itself here upon completing + * its internal initialization. This applies to both linked and loaded + * device drivers. The interface must be registered before a signalling + * manager can be attached. + * + * Arguments: + * cup pointer to interface's common unit structure + * name pointer to device name string + * sdp pointer to interface's stack services + * + * Returns: + * 0 registration successful + * errno registration failed - reason indicated + * + */ +int +atm_physif_register(cup, name, sdp) + Cmn_unit *cup; + char *name; + struct stack_defn *sdp; +{ + struct atm_pif *pip; + int s; + + /* + * See if we need to be initialized + */ + if (!atm_init) + atm_initialize(); + + /* + * Make sure we're not already registered + */ + if (cup->cu_flags & CUF_REGISTER) { + return (EALREADY); + } + + s = splnet(); + + /* + * Make sure an interface is only registered once + */ + for (pip = atm_interface_head; pip != NULL; pip = pip->pif_next) { + if ((cup->cu_unit == pip->pif_unit) && + (strcmp(name, pip->pif_name) == 0)) { + (void) splx(s); + return (EEXIST); + } + } + + /* + * Fill in physical interface parameters + */ + pip = &cup->cu_pif; + pip->pif_name = name; + pip->pif_unit = cup->cu_unit; + pip->pif_flags = PIF_UP; + pip->pif_services = sdp; + pip->pif_ioctl = atm_physif_ioctl; + + /* + * Link in the interface and mark us registered + */ + LINK2TAIL(pip, struct atm_pif, atm_interface_head, pif_next); + cup->cu_flags |= CUF_REGISTER; + + (void) splx(s); + return (0); +} + + +/* + * De-register an ATM physical interface + * + * Each ATM interface must de-register itself before downing the interface. + * The interface's signalling manager will be detached and any network + * interface and VCC control blocks will be freed. + * + * Arguments: + * cup pointer to interface's common unit structure + * + * Returns: + * 0 de-registration successful + * errno de-registration failed - reason indicated + * + */ +int +atm_physif_deregister(cup) + Cmn_unit *cup; +{ + struct atm_pif *pip = (struct atm_pif *)&cup->cu_pif; + Cmn_vcc *cvp; + int err; + int s = splnet(); + + /* + * Detach and deregister, if needed + */ + if ((cup->cu_flags & CUF_REGISTER)) { + + /* + * Detach from signalling manager + */ + if (pip->pif_sigmgr != NULL) { + err = atm_sigmgr_detach(pip); + if (err && (err != ENOENT)) { + (void) splx(s); + return (err); + } + } + + /* + * Make sure signalling manager is detached + */ + if (pip->pif_sigmgr != NULL) { + (void) splx(s); + return (EBUSY); + } + + /* + * Unlink interface + */ + UNLINK(pip, struct atm_pif, atm_interface_head, pif_next); + + cup->cu_flags &= ~CUF_REGISTER; + } + + /* + * Free all of our network interfaces + */ + atm_physif_freenifs(pip); + + /* + * Free unit's vcc information + */ + cvp = cup->cu_vcc; + while (cvp) { + atm_free(cvp); + cvp = cvp->cv_next; + } + cup->cu_vcc = (Cmn_vcc *)NULL; + + (void) splx(s); + + return (0); +} + + +/* + * Free all network interfaces on a physical interface + * + * Arguments + * pip pointer to physical interface structure + * + * Returns + * none + * + */ +void +atm_physif_freenifs(pip) + struct atm_pif *pip; +{ + struct atm_nif *nip = pip->pif_nif; + int s = splnet(); + + while ( nip ) + { + /* + * atm_nif_detach zeros pointers - save so we can + * walk the chain. + */ + struct atm_nif *nipp = nip->nif_pnext; + + /* + * Clean up network i/f trails + */ + atm_nif_detach ( nip ); + atm_free ((caddr_t)nip); + nip = nipp; + } + pip->pif_nif = (struct atm_nif *)NULL; + + (void) splx(s); + + return; +} + + +/* + * Handle physical interface ioctl's + * + * See <netatm/atm_ioctl.h> for definitions. + * + * Called at splnet. + * + * Arguments: + * code Ioctl function (sub)code + * data Data block. On input contains command, + * on output, contains results + * arg Optional code specific arguments + * + * Returns: + * 0 Request processed successfully + * errno Request failed - reason code + * + */ +static int +atm_physif_ioctl(code, data, arg) + int code; + caddr_t data; + caddr_t arg; +{ + struct atminfreq *aip = (struct atminfreq *)data; + struct atmsetreq *asr = (struct atmsetreq *)data; + struct atm_pif *pip; + struct atm_nif *nip; + struct sigmgr *smp; + struct siginst *sip; + struct ifnet *ifp; + Cmn_unit *cup; + Atm_config *acp; + caddr_t buf = aip->air_buf_addr; + struct air_phy_stat_rsp *apsp; + struct air_int_rsp apr; + struct air_netif_rsp anr; + struct air_cfg_rsp acr; + int count, len, buf_len = aip->air_buf_len; + int err = 0; + char ifname[2*IFNAMSIZ]; +#if (defined(BSD) && (BSD >= 199103)) + struct ifaddr *ifa; + struct in_ifaddr *ia; + struct sockaddr_dl *sdl; +#endif + + + switch ( aip->air_opcode ) { + + case AIOCS_INF_INT: + /* + * Get physical interface information + */ + aip = (struct atminfreq *)data; + pip = (struct atm_pif *)arg; + + /* + * Make sure there's room in user buffer + */ + if (aip->air_buf_len < sizeof(apr)) { + err = ENOSPC; + break; + } + + /* + * Fill in info to be returned + */ + KM_ZERO((caddr_t)&apr, sizeof(apr)); + smp = pip->pif_sigmgr; + sip = pip->pif_siginst; + (void) sprintf(apr.anp_intf, "%s%d", pip->pif_name, + pip->pif_unit ); + if ( pip->pif_nif ) + { + strcpy(apr.anp_nif_pref, pip->pif_nif->nif_if.if_name); + + nip = pip->pif_nif; + while ( nip ) { + apr.anp_nif_cnt++; + nip = nip->nif_pnext; + } + } + if (sip) { + ATM_ADDR_COPY(&sip->si_addr, &apr.anp_addr); + ATM_ADDR_COPY(&sip->si_subaddr, &apr.anp_subaddr); + apr.anp_sig_proto = smp->sm_proto; + apr.anp_sig_state = sip->si_state; + } + + /* + * Copy data to user buffer + */ + err = copyout((caddr_t)&apr, aip->air_buf_addr, sizeof(apr)); + if (err) + break; + + /* + * Update buffer pointer/count + */ + aip->air_buf_addr += sizeof(apr); + aip->air_buf_len -= sizeof(apr); + break; + + case AIOCS_INF_NIF: + /* + * Get network interface information + */ + aip = (struct atminfreq *)data; + nip = (struct atm_nif *)arg; + ifp = &nip->nif_if; + pip = nip->nif_pif; + + /* + * Make sure there's room in user buffer + */ + if (aip->air_buf_len < sizeof(anr)) { + err = ENOSPC; + break; + } + + /* + * Fill in info to be returned + */ + KM_ZERO((caddr_t)&anr, sizeof(anr)); + (void) sprintf(anr.anp_intf, "%s%d", ifp->if_name, + ifp->if_unit); + IFP_TO_IA(ifp, ia); + if (ia) { + anr.anp_proto_addr = *ia->ia_ifa.ifa_addr; + } + (void) sprintf(anr.anp_phy_intf, "%s%d", pip->pif_name, + pip->pif_unit); + + /* + * Copy data to user buffer + */ + err = copyout((caddr_t)&anr, aip->air_buf_addr, sizeof(anr)); + if (err) + break; + + /* + * Update buffer pointer/count + */ + aip->air_buf_addr += sizeof(anr); + aip->air_buf_len -= sizeof(anr); + break; + + case AIOCS_INF_PIS: + /* + * Get per interface statistics + */ + pip = (struct atm_pif *)arg; + if ( pip == NULL ) + return ( ENXIO ); + sprintf ( ifname, "%s%d", pip->pif_name, pip->pif_unit ); + + /* + * Cast response into users buffer + */ + apsp = (struct air_phy_stat_rsp *)buf; + + /* + * Sanity check + */ + len = sizeof ( struct air_phy_stat_rsp ); + if ( buf_len < len ) + return ( ENOSPC ); + + /* + * Copy interface name into response + */ + if ( err = copyout ( ifname, apsp->app_intf, IFNAMSIZ ) ) + break; + + /* + * Copy counters + */ + if ( err = copyout ( &pip->pif_ipdus, &apsp->app_ipdus, + len - sizeof ( apsp->app_intf ) ) ) + break; + + /* + * Adjust buffer elements + */ + buf += len; + buf_len -= len; + + aip->air_buf_addr = buf; + aip->air_buf_len = buf_len; + break; + + case AIOCS_SET_NIF: + /* + * Set NIF - allow user to configure 1 or more logical + * interfaces per physical interface. + */ + + /* + * Get pointer to physical interface structure from + * ioctl argument. + */ + pip = (struct atm_pif *)arg; + cup = (Cmn_unit *)pip; + + /* + * Sanity check - are we already connected to something? + */ + if ( pip->pif_sigmgr ) + { + err = EBUSY; + break; + } + + /* + * Free any previously allocated NIFs + */ + atm_physif_freenifs(pip); + + /* + * Add list of interfaces + */ + for ( count = 0; count < asr->asr_nif_cnt; count++ ) + { + nip = (struct atm_nif *)atm_allocate(cup->cu_nif_pool); + if ( nip == NULL ) + { + /* + * Destroy any successful nifs + */ + atm_physif_freenifs(pip); + err = ENOMEM; + break; + } + + nip->nif_pif = pip; + ifp = &nip->nif_if; + + strcpy ( nip->nif_name, asr->asr_nif_pref ); + nip->nif_sel = count; + + ifp->if_name = nip->nif_name; + ifp->if_unit = count; + ifp->if_mtu = ATM_NIF_MTU; + ifp->if_flags = IFF_UP | IFF_BROADCAST | IFF_RUNNING; + ifp->if_output = atm_ifoutput; + ifp->if_ioctl = atm_if_ioctl; + ifp->if_snd.ifq_maxlen = ifqmaxlen; +#if (defined(BSD) && (BSD >= 199103)) + /* + * Set if_type and if_baudrate + */ + ifp->if_type = IFT_ATM; + switch ( cup->cu_config.ac_media ) { + case MEDIA_TAXI_100: + ifp->if_baudrate = 100000000; + break; + case MEDIA_TAXI_140: + ifp->if_baudrate = 140000000; + break; + case MEDIA_OC3C: + case MEDIA_OC12C: + case MEDIA_UTP155: + ifp->if_baudrate = 155000000; + break; + } +#endif + + if ( err = atm_nif_attach ( nip ) ) + { + atm_free ( (caddr_t)nip ); + + /* + * Destroy any successful nifs + */ + atm_physif_freenifs(pip); + break; + } +#if (defined(BSD) && (BSD >= 199103)) + /* + * Set macaddr in <Link> address + */ + ifp->if_addrlen = 6; + ifa = ifnet_addrs[ifp->if_index - 1]; + if ( ifa ) { + sdl = (struct sockaddr_dl *) + ifa->ifa_addr; + sdl->sdl_type = IFT_ETHER; + sdl->sdl_alen = ifp->if_addrlen; + bcopy ( (caddr_t)&cup->cu_config.ac_macaddr, + LLADDR(sdl), ifp->if_addrlen ); + } +#endif + } + break; + + case AIOCS_INF_CFG: + /* + * Get adapter configuration information + */ + aip = (struct atminfreq *)data; + pip = (struct atm_pif *)arg; + cup = (Cmn_unit *)pip; + acp = &cup->cu_config; + + /* + * Make sure there's room in user buffer + */ + if (aip->air_buf_len < sizeof(acr)) { + err = ENOSPC; + break; + } + + /* + * Fill in info to be returned + */ + KM_ZERO((caddr_t)&acr, sizeof(acr)); + (void) sprintf(acr.acp_intf, "%s%d", pip->pif_name, + pip->pif_unit); + KM_COPY((caddr_t)acp, (caddr_t)&acr.acp_cfg, + sizeof(Atm_config)); + + /* + * Copy data to user buffer + */ + err = copyout((caddr_t)&acr, aip->air_buf_addr, + sizeof(acr)); + if (err) + break; + + /* + * Update buffer pointer/count + */ + aip->air_buf_addr += sizeof(acr); + aip->air_buf_len -= sizeof(acr); + break; + + case AIOCS_INF_VST: + /* + * Pass off to device-specific handler + */ + cup = (Cmn_unit *)arg; + if (cup == NULL) + err = ENXIO; + else + err = (*cup->cu_ioctl)(code, data, arg); + break; + + default: + err = ENOSYS; + } + + return ( err ); +} + + +/* + * Register a Network Convergence Module + * + * Each ATM network convergence module must register itself here before + * it will receive network interface status notifications. + * + * Arguments: + * ncp pointer to network convergence definition structure + * + * Returns: + * 0 registration successful + * errno registration failed - reason indicated + * + */ +int +atm_netconv_register(ncp) + struct atm_ncm *ncp; +{ + struct atm_ncm *tdp; + int s = splnet(); + + /* + * See if we need to be initialized + */ + if (!atm_init) + atm_initialize(); + + /* + * Validate protocol family + */ + if (ncp->ncm_family > AF_MAX) { + (void) splx(s); + return (EINVAL); + } + + /* + * Ensure no duplicates + */ + for (tdp = atm_netconv_head; tdp != NULL; tdp = tdp->ncm_next) { + if (tdp->ncm_family == ncp->ncm_family) { + (void) splx(s); + return (EEXIST); + } + } + + /* + * Add module to list + */ + LINK2TAIL(ncp, struct atm_ncm, atm_netconv_head, ncm_next); + + /* + * Add new interface output function + */ + atm_ifouttbl[ncp->ncm_family] = ncp->ncm_ifoutput; + + (void) splx(s); + return (0); +} + + +/* + * De-register an ATM Network Convergence Module + * + * Each ATM network convergence provider must de-register its registered + * service(s) before terminating. Specifically, loaded kernel modules + * must de-register their services before unloading themselves. + * + * Arguments: + * ncp pointer to network convergence definition structure + * + * Returns: + * 0 de-registration successful + * errno de-registration failed - reason indicated + * + */ +int +atm_netconv_deregister(ncp) + struct atm_ncm *ncp; +{ + int found, s = splnet(); + + /* + * Remove module from list + */ + UNLINKF(ncp, struct atm_ncm, atm_netconv_head, ncm_next, found); + + if (!found) { + (void) splx(s); + return (ENOENT); + } + + /* + * Remove module's interface output function + */ + atm_ifouttbl[ncp->ncm_family] = NULL; + + (void) splx(s); + return (0); +} + + +/* + * Attach an ATM Network Interface + * + * Before an ATM network interface can be used by the system, the owning + * device interface must attach the network interface using this function. + * The physical interface for this network interface must have been previously + * registered (using atm_interface_register). The network interface will be + * added to the kernel's interface list and to the physical interface's list. + * The caller is responsible for initializing the control block fields. + * + * Arguments: + * nip pointer to atm network interface control block + * + * Returns: + * 0 attach successful + * errno attach failed - reason indicated + * + */ +int +atm_nif_attach(nip) + struct atm_nif *nip; +{ + struct atm_pif *pip, *pip2; + struct ifnet *ifp; + struct atm_ncm *ncp; + int s; + + ifp = &nip->nif_if; + pip = nip->nif_pif; + + s = splimp(); + + /* + * Verify physical interface is registered + */ + for (pip2 = atm_interface_head; pip2 != NULL; pip2 = pip2->pif_next) { + if (pip == pip2) + break; + } + if ((pip == NULL) || (pip2 == NULL)) { + (void) splx(s); + return (EFAULT); + } + + /* + * Add to system interface list + */ + if_attach(ifp); + + /* + * Add to physical interface list + */ + LINK2TAIL(nip, struct atm_nif, pip->pif_nif, nif_pnext); + + /* + * Notify network convergence modules of new network i/f + */ + for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) { + int err; + + err = (*ncp->ncm_stat)(NCM_ATTACH, nip, 0); + if (err) { + atm_nif_detach(nip); + (void) splx(s); + return (err); + } + } + + (void) splx(s); + return (0); +} + + +/* + * Detach an ATM Network Interface + * + * Before an ATM network interface control block can be freed, all kernel + * references to/from this block must be released. This function will delete + * all routing references to the interface and free all interface addresses + * for the interface. The network interface will then be removed from the + * kernel's interface list and from the owning physical interface's list. + * The caller is responsible for free'ing the control block. + * + * Arguments: + * nip pointer to atm network interface control block + * + * Returns: + * none + * + */ +void +atm_nif_detach(nip) + struct atm_nif *nip; +{ + struct atm_ncm *ncp; + int s, i; + struct ifnet *ifp = &nip->nif_if; + struct ifaddr *ifa; + struct in_ifaddr *ia; + struct radix_node_head *rnh; + + + s = splimp(); + + /* + * Notify convergence modules of network i/f demise + */ + for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) { + (void) (*ncp->ncm_stat)(NCM_DETACH, nip, 0); + } + + /* + * Mark interface down + */ + if_down(ifp); + + /* + * Free all interface routes and addresses + */ + while (1) { + IFP_TO_IA(ifp, ia); + if (ia == NULL) + break; + + /* Delete interface route */ + in_ifscrub(ifp, ia); + + /* Remove interface address from queues */ + ifa = &ia->ia_ifa; + TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); + TAILQ_REMOVE(&in_ifaddrhead, ia, ia_link); + + /* Free interface address */ + IFAFREE(ifa); + } + + /* + * Delete all remaining routes using this interface + * Unfortuneatly the only way to do this is to slog through + * the entire routing table looking for routes which point + * to this interface...oh well... + */ + for (i = 1; i <= AF_MAX; i++) { + if ((rnh = rt_tables[i]) == NULL) + continue; + (void) rnh->rnh_walktree(rnh, atm_netif_rtdel, ifp); + } + + /* + * Remove from system interface list (ie. if_detach()) + */ + TAILQ_REMOVE(&ifnet, ifp, if_link); + + /* + * Remove from physical interface list + */ + UNLINK(nip, struct atm_nif, nip->nif_pif->pif_nif, nif_pnext); + + (void) splx(s); +} + + +/* + * Delete Routes for a Network Interface + * + * Called for each routing entry via the rnh->rnh_walktree() call above + * to delete all route entries referencing a detaching network interface. + * + * Arguments: + * rn pointer to node in the routing table + * arg argument passed to rnh->rnh_walktree() - detaching interface + * + * Returns: + * 0 successful + * errno failed - reason indicated + * + */ +static int +atm_netif_rtdel(rn, arg) + struct radix_node *rn; + void *arg; +{ + struct rtentry *rt = (struct rtentry *)rn; + struct ifnet *ifp = arg; + int err; + + if (rt->rt_ifp == ifp) { + + /* + * Protect (sorta) against walktree recursion problems + * with cloned routes + */ + if ((rt->rt_flags & RTF_UP) == 0) + return (0); + + err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, + rt_mask(rt), rt->rt_flags, + (struct rtentry **) NULL); + if (err) { + log(LOG_WARNING, "atm_netif_rtdel: error %d\n", err); + } + } + + return (0); +} + + +/* + * Set an ATM Network Interface address + * + * This is called from a device interface when processing an SIOCSIFADDR + * ioctl request. We just notify all convergence modules of the new address + * and hope everyone has non-overlapping interests, since if someone reports + * an error we don't go back and tell everyone to undo the change. + * + * Arguments: + * nip pointer to atm network interface control block + * ifa pointer to new interface address + * + * Returns: + * 0 set successful + * errno set failed - reason indicated + * + */ +int +atm_nif_setaddr(nip, ifa) + struct atm_nif *nip; + struct ifaddr *ifa; +{ + struct atm_ncm *ncp; + int err = 0, s = splnet(); + + /* + * Notify convergence modules of network i/f change + */ + for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) { + err = (*ncp->ncm_stat)(NCM_SETADDR, nip, (int)ifa); + if (err) + break; + } + (void) splx(s); + + return (err); +} + + +/* + * ATM Interface Packet Output + * + * All ATM network interfaces must have their ifnet if_output address set to + * this function. Since no existing network layer code is to be modified + * for ATM support, this function serves as the hook to allow network output + * packets to be assigned to their proper outbound VCC. Each network address + * family which is to be supported over ATM must be assigned an output + * packet processing function via atm_netconv_register(). + * + * Arguments: + * ifp pointer to ifnet structure + * m pointer to packet buffer chain to be output + * dst pointer to packet's network destination address + * + * Returns: + * 0 packet queued to interface + * errno output failed - reason indicated + * + */ +int +#if (defined(BSD) && (BSD >= 199103)) +atm_ifoutput(ifp, m, dst, rt) +#else +atm_ifoutput(ifp, m, dst) +#endif + struct ifnet *ifp; + KBuffer *m; + struct sockaddr *dst; +#if (defined(BSD) && (BSD >= 199103)) + struct rtentry *rt; +#endif +{ + u_short fam = dst->sa_family; + int (*func)__P((struct ifnet *, KBuffer *, + struct sockaddr *)); + + /* + * Validate address family + */ + if (fam > AF_MAX) { + KB_FREEALL(m); + return (EAFNOSUPPORT); + } + + /* + * Hand packet off for dst-to-VCC mapping + */ + func = atm_ifouttbl[fam]; + if (func == NULL) { + KB_FREEALL(m); + return (EAFNOSUPPORT); + } + return ((*func)(ifp, m, dst)); +} + + +/* + * Handle interface ioctl requests. + * + * Arguments: + * ifp pointer to network interface structure + * cmd IOCTL cmd + * data arguments to/from ioctl + * + * Returns: + * error errno value + */ +static int +atm_if_ioctl(ifp, cmd, data) + struct ifnet *ifp; + u_long cmd; + caddr_t data; +{ + register struct ifreq *ifr = (struct ifreq *)data; + struct atm_nif *nip = (struct atm_nif *)ifp; + int error = 0; + int s = splnet(); + + switch ( cmd ) + { + case SIOCGIFADDR: + KM_COPY ( (caddr_t)&(nip->nif_pif->pif_macaddr), + (caddr_t)ifr->ifr_addr.sa_data, + sizeof(struct mac_addr) ); + break; + + case SIOCSIFADDR: + error = atm_nif_setaddr ( nip, (struct ifaddr *)data); + ifp->if_flags |= IFF_UP | IFF_RUNNING | IFF_BROADCAST; + break; + + case SIOCGIFFLAGS: + *(short *)data = ifp->if_flags; + break; + + case SIOCSIFFLAGS: + break; + + default: + error = EINVAL; + break; + } + + (void) splx(s); + return ( error ); +} + + +/* + * Parse interface name + * + * Parses an interface name string into a name and a unit component. + * + * Arguments: + * name pointer to interface name string + * namep address to store interface name + * size size available at namep + * unitp address to store interface unit number + * + * Returns: + * 0 name parsed + * else parse error + * + */ +static int +atm_ifparse(name, namep, size, unitp) + char *name; + char *namep; + int size; + int *unitp; +{ + char *cp, *np; + int len = 0, unit = 0; + + /* + * Separate supplied string into name and unit parts. + */ + cp = name; + np = namep; + while (*cp) { + if (*cp >= '0' && *cp <= '9') + break; + if (++len >= size) + return (-1); + *np++ = *cp++; + } + *np = '\0'; + while (*cp && *cp >= '0' && *cp <= '9') + unit = 10 * unit + *cp++ - '0'; + + *unitp = unit; + + return (0); +} + + +/* + * Locate ATM physical interface via name + * + * Uses the supplied interface name string to locate a registered + * ATM physical interface. + * + * Arguments: + * name pointer to interface name string + * + * Returns: + * 0 interface not found + * else pointer to atm physical interface structure + * + */ +struct atm_pif * +atm_pifname(name) + char *name; +{ + struct atm_pif *pip; + char n[IFNAMSIZ]; + int unit; + + /* + * Break down name + */ + if (atm_ifparse(name, n, sizeof(n), &unit)) + return ((struct atm_pif *)0); + + /* + * Look for the physical interface + */ + for (pip = atm_interface_head; pip; pip = pip->pif_next) { + if ((pip->pif_unit == unit) && (strcmp(pip->pif_name, n) == 0)) + break; + } + + return (pip); +} + + +/* + * Locate ATM network interface via name + * + * Uses the supplied interface name string to locate an ATM network interface. + * + * Arguments: + * name pointer to interface name string + * + * Returns: + * 0 interface not found + * else pointer to atm network interface structure + * + */ +struct atm_nif * +atm_nifname(name) + char *name; +{ + struct atm_pif *pip; + struct atm_nif *nip; + char n[IFNAMSIZ]; + int unit; + + /* + * Break down name + */ + if (atm_ifparse(name, n, sizeof(n), &unit)) + return ((struct atm_nif *)0); + + /* + * Search thru each physical interface + */ + for (pip = atm_interface_head; pip; pip = pip->pif_next) { + /* + * Looking for network interface + */ + for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) { + struct ifnet *ifp = (struct ifnet *)nip; + if ((ifp->if_unit == unit) && + (strcmp(ifp->if_name, n) == 0)) + return (nip); + } + } + return (NULL); +} + diff --git a/sys/netatm/atm_if.h b/sys/netatm/atm_if.h new file mode 100644 index 0000000..ccf9d03 --- /dev/null +++ b/sys/netatm/atm_if.h @@ -0,0 +1,392 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_if.h,v 1.13 1998/08/07 22:10:37 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * ATM Physical and Network Interface definitions + * + */ + +#ifndef _NETATM_ATM_IF_H +#define _NETATM_ATM_IF_H + +/* + * Handy constants + */ +#define ATM_NIF_MTU 9180 /* Default network interface MTU */ + +#define ATM_PCR_TAXI100 227273 /* Peak Cell Rate for 100 Mbs TAXI */ +#define ATM_PCR_TAXI140 318181 /* Peak Cell Rate for 140 Mbs TAXI */ +#define ATM_PCR_OC3C 353207 /* Peak Cell Rate for OC3c */ +#define ATM_PCR_OC12C 1416905 /* Peak Cell Rate for OC12c */ + + +/* + * Media Access Control (MAC) address + */ +struct mac_addr { + u_char ma_data[6]; /* MAC address */ +}; +typedef struct mac_addr Mac_addr; + + +/* + * Adapter vendor identifiers + */ +enum atm_vendor { + VENDOR_UNKNOWN, /* Unknown vendor */ + VENDOR_FORE, /* FORE Systems, Inc. */ + VENDOR_ENI /* Efficient Networks, Inc. */ +}; +typedef enum atm_vendor Atm_vendor; + + +/* + * Adapter vendor interface identifiers + */ +enum atm_vendapi { + VENDAPI_UNKNOWN, /* Unknown interface */ + VENDAPI_FORE_1, /* FORE - 200 Series */ + VENDAPI_ENI_1 /* ENI - Midway */ +}; +typedef enum atm_vendapi Atm_vendapi; + + +/* + * Adapter device model identifiers + */ +enum atm_device { + DEV_UNKNOWN, /* Unknown device */ + DEV_FORE_SBA200E, /* FORE SBA-200E */ + DEV_FORE_SBA200, /* FORE SBA-200 */ + DEV_FORE_PCA200E, /* FORE PCA-200E */ + DEV_ENI_155P /* ENI-155p */ +}; +typedef enum atm_device Atm_device; + + +/* + * Adapter media identifiers + */ +enum atm_media { + MEDIA_UNKNOWN, /* Unknown media type */ + MEDIA_TAXI_100, /* TAXI - 100 Mbps */ + MEDIA_TAXI_140, /* TAXI - 140 Mbps */ + MEDIA_OC3C, /* OC-3C */ + MEDIA_OC12C, /* OC-12C */ + MEDIA_UTP155 /* UTP-155 */ +}; +typedef enum atm_media Atm_media; + + +/* + * Bus type identifiers + */ +enum atm_bus { + BUS_UNKNOWN, /* Unknown bus type */ + BUS_SBUS_B16, /* SBus: 16 byte (4 word) max burst */ + BUS_SBUS_B32, /* SBus: 32 byte (8 word) max burst */ + BUS_PCI /* PCI */ +}; +typedef enum atm_bus Atm_bus; + + +#define VERSION_LEN 16 /* Length of version info string */ + + +/* + * ATM adapter configuration information structure + */ +struct atm_config { + Atm_vendor ac_vendor; /* Vendor */ + Atm_vendapi ac_vendapi; /* Vendor interface */ + Atm_device ac_device; /* Device model */ + Atm_media ac_media; /* Media type */ + u_long ac_serial; /* Serial number */ + Atm_bus ac_bustype; /* Bus type */ + u_long ac_busslot; /* Bus slot info (bus type dependent) */ + u_long ac_ram; /* Device ram offset */ + u_long ac_ramsize; /* Device ram size */ + Mac_addr ac_macaddr; /* MAC address */ + char ac_hard_vers[VERSION_LEN]; /* Hardware version */ + char ac_firm_vers[VERSION_LEN]; /* Firmware version */ +}; +typedef struct atm_config Atm_config; + + +#ifdef ATM_KERNEL +/* + * Common structure used to define each physical ATM device interface. + * This structure will (normally) be embedded at the top of each driver's + * device-specific interface structure. + */ +struct atm_pif { + struct atm_pif *pif_next; /* Next registered atm interface */ + char *pif_name; /* Device name */ + short pif_unit; /* Device unit number */ + u_char pif_flags; /* Interface flags (see below) */ + struct sigmgr *pif_sigmgr; /* Signalling Manager for interface */ + struct siginst *pif_siginst; /* Signalling protocol instance */ + struct stack_defn *pif_services; /* Interface's stack services */ + struct mac_addr pif_macaddr; /* Interface's MAC address */ + struct atm_nif *pif_nif; /* List of network interfaces */ + struct atm_pif *pif_grnext; /* Next atm device in group */ + +/* Exported functions */ + int (*pif_ioctl) /* Interface ioctl handler */ + __P((int, caddr_t, caddr_t)); + +/* Interface statistics */ + long pif_ipdus; /* PDUs received from interface */ + long pif_opdus; /* PDUs sent to interface */ + long pif_ibytes; /* Bytes received from interface */ + long pif_obytes; /* Bytes sent to interface */ + long pif_ierrors; /* Errors receiving from interface */ + long pif_oerrors; /* Errors sending to interface */ + long pif_cmderrors; /* Interface command errors */ + caddr_t pif_cardstats; /* Card specific statistics */ + +/* Interface capabilities */ + u_short pif_maxvpi; /* Maximum VPI value supported */ + u_short pif_maxvci; /* Maximum VCI value supported */ + u_int pif_pcr; /* Peak Cell Rate */ +}; + +/* + * Physical interface flags + */ +#define PIF_UP 0x01 /* Interface is up */ +#define PIF_LOOPBACK 0x02 /* Loopback local packets */ + + +/* + * Structure defining an ATM network interface. This structure is used as + * the hook between the standard BSD network layer interface mechanism and + * the ATM device layer. There may be one or more network interfaces for + * each physical ATM interface. + */ +struct atm_nif { + struct ifnet nif_if; /* Network interface */ + struct atm_pif *nif_pif; /* Our physical interface */ + char nif_name[IFNAMSIZ];/* Network interface name */ + u_char nif_sel; /* Interface's address selector */ + struct atm_nif *nif_pnext; /* Next net interface on phys i/f */ + +/* Interface statistics (in addition to ifnet stats) */ + long nif_ibytes; /* Bytes received from interface */ + long nif_obytes; /* Bytes sent to interface */ +}; + + +/* + * Common Device VCC Entry + * + * Contains the common information for each VCC which is opened + * through a particular device. + */ +struct cmn_vcc { + struct cmn_vcc *cv_next; /* Next in list */ + void *cv_toku; /* Upper layer's token */ + void (*cv_upper) /* Upper layer's interface */ + __P((int, void *, int, int)); + Atm_connvc *cv_connvc; /* Associated connection VCC */ + u_char cv_state; /* VCC state (see below) */ + u_char cv_flags; /* VCC flags (see below) */ +}; +typedef struct cmn_vcc Cmn_vcc; + +/* + * VCC States + */ +#define CVS_FREE 0 /* Not allocated */ +#define CVS_INST 1 /* Instantiated, waiting for INIT */ +#define CVS_INITED 2 /* Initialized, waiting for driver */ +#define CVS_ACTIVE 3 /* Device activated by driver */ +#define CVS_PTERM 4 /* Waiting for TERM */ +#define CVS_TERM 5 /* Terminated */ + +/* + * VCC Flags + */ +#define CVF_RSVD 0x0f /* Reserved for device-specific use */ + + +/* + * Common Device Unit Structure + * + * Contains the common information for a single device (adapter). + */ +struct cmn_unit { + struct atm_pif cu_pif; /* Physical interface */ + u_int cu_unit; /* Local unit number */ + u_char cu_flags; /* Device flags (see below) */ + u_int cu_mtu; /* Interface MTU */ + + u_int cu_open_vcc; /* Open VCC count */ + Cmn_vcc *cu_vcc; /* List of VCC's on interface */ + + u_int cu_intrpri; /* Highest unit interrupt priority */ + int cu_savepri; /* Saved priority for locking device */ + + struct sp_info *cu_vcc_pool; /* Device VCC pool */ + struct sp_info *cu_nif_pool; /* Device NIF pool */ + + int (*cu_ioctl) /* Interface ioctl handler */ + __P((int, caddr_t, caddr_t)); + int (*cu_instvcc) /* VCC stack instantion handler */ + __P((struct cmn_unit *, Cmn_vcc *)); + int (*cu_openvcc) /* Open VCC handler */ + __P((struct cmn_unit *, Cmn_vcc *)); + int (*cu_closevcc) /* Close VCC handler */ + __P((struct cmn_unit *, Cmn_vcc *)); + void (*cu_output) /* Data output handler */ + __P((struct cmn_unit *, Cmn_vcc *, KBuffer *)); + + Atm_config cu_config; /* Device configuration data */ +}; +typedef struct cmn_unit Cmn_unit; + +/* + * Device flags + */ +#define CUF_REGISTER 0x01 /* Device is registered */ +#define CUF_INITED 0x02 /* Device is initialized */ + + +/* + * Structure used to define a network convergence module and its associated + * entry points. A convergence module is used to provide the interface + * translations necessary between the ATM system and the BSD network layer + * interface mechanism. There will be one network convergence module for + * each protocol address family supporting ATM connections. + */ +struct atm_ncm { + struct atm_ncm *ncm_next; /* Next in registry list */ + u_short ncm_family; /* Protocol family */ +/* Exported functions */ + int (*ncm_ifoutput) /* Interface if_output handler */ + __P((struct ifnet *, KBuffer *, + struct sockaddr *)); + int (*ncm_stat) /* Network i/f status handler */ + __P((int, struct atm_nif *, int)); +}; + +/* + * ncm_stat() commands + */ +#define NCM_ATTACH 1 /* Attaching a new net i/f */ +#define NCM_DETACH 2 /* Detaching a current net i/f */ +#define NCM_SETADDR 3 /* Net i/f address change */ +#define NCM_SIGATTACH 4 /* Attaching a signalling manager */ +#define NCM_SIGDETACH 5 /* Detaching a signalling manager */ + + +/* + * atm_dev_alloc() parameters + */ +#define ATM_DEV_NONCACHE 1 /* Allocate non-cacheable memory */ + +/* + * atm_dev_compress() buffer allocation sizes + */ +#if defined(BSD) +#define ATM_DEV_CMPR_LG MCLBYTES /* Size of large buffers */ +#define ATM_DEV_CMPR_SM MLEN /* Size of small buffers */ +#endif + +/* + * Macros to manage DMA addresses + */ +#if defined(sun4c) +#define DMA_INIT() +#define DMA_GET_ADDR(addr,len,align,flags) ((void *)(addr)) +#define DMA_FREE_ADDR(addr,daddr,len,flags) +#define DMA_RELEASE() + +#elif defined(sun4m) +#define DMA_INIT() +#define DMA_GET_ADDR(addr,len,align,flags) \ + (void *)atm_dma_map((addr),(len),(flags)) +#define DMA_FREE_ADDR(addr,daddr,len,flags) \ + (void)atm_dma_free((daddr),(flags)) +#define DMA_RELEASE() + +#elif defined(BSD) && defined(__i386__) +#define DMA_INIT() +#define DMA_GET_ADDR(addr,len,align,flags) ((void *)vtophys(addr)) +#define DMA_FREE_ADDR(addr,daddr,len,flags) +#define DMA_RELEASE() + +#else + #error - Must define hardware-specific requirements here +#endif + + +/* + * Macros to lock out device interrupts + */ +#if defined(sun) +#define DEVICE_LOCK(u) ((u)->cu_savepri = splr((u)->cu_intrpri)) +#endif +#if defined(__FreeBSD__) +#define DEVICE_LOCK(u) ((u)->cu_savepri = splimp()) +#endif +#define DEVICE_UNLOCK(u) ((void) splx((u)->cu_savepri)) + + +/* + * SBus defines + */ +#if defined(sun) +#define SBUS_BURST32 0x20 /* Device supports 32-byte bursts */ +#endif + + +/* + * Macro to schedule the ATM interrupt queue handler + */ +typedef void (atm_intr_t) __P((void *, KBuffer *)); /* Callback function type */ +typedef atm_intr_t *atm_intr_func_t; /* Pointer to callback function */ + +#ifdef sun +#define SCHED_ATM schednetisr(atm_intr) +#endif +#ifdef __FreeBSD__ +#define NETISR_ATM AF_ATM +#define SCHED_ATM schednetisr(NETISR_ATM) +#endif +#ifdef sgi +extern int atm_intr_index; +#define SCHED_ATM schednetisr(atm_intr_index) +#endif +#endif /* ATM_KERNEL */ + +#endif /* _NETATM_ATM_IF_H */ diff --git a/sys/netatm/atm_ioctl.h b/sys/netatm/atm_ioctl.h new file mode 100644 index 0000000..a38d183 --- /dev/null +++ b/sys/netatm/atm_ioctl.h @@ -0,0 +1,432 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_ioctl.h,v 1.9 1998/08/26 23:29:01 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * PF_ATM socket ioctl definitions + * + */ + +#ifndef _NETATM_ATM_IOCTL_H +#define _NETATM_ATM_IOCTL_H + + +/* + * Structure for PF_ATM configure (AIOCCFG) socket ioctls + */ +struct atmcfgreq { + int acr_opcode; /* Sub-operation */ + union { + struct { + /* Configure - attach */ + char acru_att_intf[IFNAMSIZ];/* Interface name */ + u_char acru_att_proto; /* Signalling protocol */ + } acru_att; + struct { + /* Configure - detach */ + char acru_det_intf[IFNAMSIZ];/* Interface name */ + } acru_det; + } acr_u; +}; +#define acr_att_intf acr_u.acru_att.acru_att_intf +#define acr_att_proto acr_u.acru_att.acru_att_proto +#define acr_det_intf acr_u.acru_det.acru_det_intf + + +/* + * Structure for PF_ATM set (AIOCSET) socket ioctls + */ +struct atmsetreq { + int asr_opcode; /* Sub-operation */ + union { + /* ARP server */ + struct { + char asru_arp_intf[IFNAMSIZ];/* Interface name */ + Atm_addr asru_arp_addr; /* ARP srvr address */ + Atm_addr asru_arp_subaddr;/* ARP srvr subaddr */ + caddr_t asru_arp_pbuf; /* Prefix buffer addr */ + int asru_arp_plen; /* Prefix buffer len */ + } asru_asrvr; + /* MAC address */ + struct { + char asru_mac_intf[IFNAMSIZ];/* Interface name */ + struct mac_addr asru_mac_addr; /* MAC address */ + } asru_mac; + /* Network interface */ + struct { + char asru_nif_intf[IFNAMSIZ];/* Interface name */ + char asru_nif_pref[IFNAMSIZ];/* I/f prefix name */ + int asru_nif_cnt; /* Number of i/fs */ + } asru_nif; + /* NSAP prefix */ + struct { + char asru_prf_intf[IFNAMSIZ];/* Interface name */ + u_char asru_prf_pref[13]; /* NSAP prefix */ + } asru_prf; + } asr_u; +}; +#define asr_arp_intf asr_u.asru_asrvr.asru_arp_intf +#define asr_arp_addr asr_u.asru_asrvr.asru_arp_addr +#define asr_arp_pbuf asr_u.asru_asrvr.asru_arp_pbuf +#define asr_arp_plen asr_u.asru_asrvr.asru_arp_plen +#define asr_arp_subaddr asr_u.asru_asrvr.asru_arp_subaddr +#define asr_mac_intf asr_u.asru_mac.asru_mac_intf +#define asr_mac_addr asr_u.asru_mac.asru_mac_addr +#define asr_nif_intf asr_u.asru_nif.asru_nif_intf +#define asr_nif_pref asr_u.asru_nif.asru_nif_pref +#define asr_nif_cnt asr_u.asru_nif.asru_nif_cnt +#define asr_prf_intf asr_u.asru_prf.asru_prf_intf +#define asr_prf_pref asr_u.asru_prf.asru_prf_pref + + +/* + * Structure for PF_ATM add (AIOCADD) socket ioctls + */ +struct atmaddreq { + int aar_opcode; /* Sub-operation */ + union { + /* Add PVC */ + struct { + char aaru_pvc_intf[IFNAMSIZ];/* Interface name */ + u_short aaru_pvc_vpi; /* VPI value */ + u_short aaru_pvc_vci; /* VCI value */ + struct sockaddr aaru_pvc_dst; /* Destination addr */ + Sap_t aaru_pvc_sap; /* Endpoint SAP */ + Aal_t aaru_pvc_aal; /* AAL */ + Encaps_t aaru_pvc_encaps; /* Encapsulation */ + u_char aaru_pvc_flags; /* Flags (see below) */ + } aaru_add_pvc; + + /* Add ARP table entry */ + struct { + char aaru_arp_intf[IFNAMSIZ];/* Interface name */ + struct sockaddr aaru_arp_dst; /* IP addr */ + Atm_addr aaru_arp_addr; /* ATM addr */ + u_char aaru_arp_origin; /* Entry origin */ + } aaru_add_arp; + } aar_u; +}; +#define aar_pvc_intf aar_u.aaru_add_pvc.aaru_pvc_intf +#define aar_pvc_vpi aar_u.aaru_add_pvc.aaru_pvc_vpi +#define aar_pvc_vci aar_u.aaru_add_pvc.aaru_pvc_vci +#define aar_pvc_dst aar_u.aaru_add_pvc.aaru_pvc_dst +#define aar_pvc_sap aar_u.aaru_add_pvc.aaru_pvc_sap +#define aar_pvc_aal aar_u.aaru_add_pvc.aaru_pvc_aal +#define aar_pvc_encaps aar_u.aaru_add_pvc.aaru_pvc_encaps +#define aar_pvc_flags aar_u.aaru_add_pvc.aaru_pvc_flags +#define aar_arp_intf aar_u.aaru_add_arp.aaru_arp_intf +#define aar_arp_dst aar_u.aaru_add_arp.aaru_arp_dst +#define aar_arp_addr aar_u.aaru_add_arp.aaru_arp_addr +#define aar_arp_origin aar_u.aaru_add_arp.aaru_arp_origin + +/* PVC flags */ +#define PVC_DYN 0x01 /* Dest addr is dynamic */ + + +/* + * Structure for PF_ATM delete (AIOCDEL) socket ioctls + */ +struct atmdelreq { + int adr_opcode; /* Sub-operation */ + union { + /* Delete PVC */ + struct { + char adru_pvc_intf[IFNAMSIZ];/* Interface name */ + u_short adru_pvc_vpi; /* VPI value */ + u_short adru_pvc_vci; /* VCI value */ + } adru_del_pvc; + + /* Delete SVC */ + struct { + char adru_svc_intf[IFNAMSIZ];/* Interface name */ + u_short adru_svc_vpi; /* VPI value */ + u_short adru_svc_vci; /* VCI value */ + } adru_del_svc; + + /* Delete ARP table entry */ + struct { + char adru_arp_intf[IFNAMSIZ];/* Interface name */ + struct sockaddr adru_arp_dst; /* IP addr */ + } adru_del_arp; + } adr_u; +}; +#define adr_pvc_intf adr_u.adru_del_pvc.adru_pvc_intf +#define adr_pvc_vpi adr_u.adru_del_pvc.adru_pvc_vpi +#define adr_pvc_vci adr_u.adru_del_pvc.adru_pvc_vci +#define adr_svc_intf adr_u.adru_del_svc.adru_svc_intf +#define adr_svc_vpi adr_u.adru_del_svc.adru_svc_vpi +#define adr_svc_vci adr_u.adru_del_svc.adru_svc_vci +#define adr_arp_intf adr_u.adru_del_arp.adru_arp_intf +#define adr_arp_dst adr_u.adru_del_arp.adru_arp_dst + + +/* + * Structure for PF_ATM information (AIOCINFO) socket ioctls + */ +struct atminfreq { + int air_opcode; /* Sub-operation */ + caddr_t air_buf_addr; /* Buffer for returned info */ + int air_buf_len; /* Buffer length */ + union { + /* Vendor info */ + char airu_vinfo_intf[IFNAMSIZ];/* Interface name */ + /* IP VCC */ + struct sockaddr airu_ip_addr; /* Destination host */ + /* ARP table */ + struct { + struct sockaddr airu_arp_addr; /* Destination host */ + u_char airu_arp_flags; /* Flags (see below) */ + } airu_arp; + /* ARP server */ + char airu_asrv_intf[IFNAMSIZ];/* Interface name */ + /* Interface */ + char airu_int_intf[IFNAMSIZ];/* Interface name */ + /* VCC */ + char airu_vcc_intf[IFNAMSIZ];/* Interface name */ + /* Configuration */ + char airu_cfg_intf[IFNAMSIZ];/* Interface name */ + /* Network interface */ + char airu_netif_intf[IFNAMSIZ];/* Interface name */ + /* Physical interface statistics */ + char airu_physt_intf[IFNAMSIZ];/* Interface name */ + } air_u; +}; +#define air_vinfo_intf air_u.airu_vinfo_intf +#define air_ip_addr air_u.airu_ip_addr +#define air_arp_addr air_u.airu_arp.airu_arp_addr +#define air_arp_flags air_u.airu_arp.airu_arp_flags +#define air_asrv_intf air_u.airu_asrv_intf +#define air_int_intf air_u.airu_int_intf +#define air_vcc_intf air_u.airu_vcc_intf +#define air_cfg_intf air_u.airu_cfg_intf +#define air_netif_intf air_u.airu_netif_intf +#define air_physt_intf air_u.airu_physt_intf + +/* ARP table info flags */ +#define ARP_RESET_REF 0x01 /* Reset refresh status */ + + +/* + * Structures returned by information requests + */ + +/* + * Vendor-specific interface information + */ +struct air_vinfo_rsp { + char avsp_intf[IFNAMSIZ]; /* Interface name */ + int avsp_len; /* Length of returned + Vendor Info block */ + /* Vendor info ... */ +}; + + +/* + * ARP table information + */ +struct air_arp_rsp { + struct sockaddr aap_arp_addr; /* Destination host */ + char aap_intf[IFNAMSIZ]; /* Interface name */ + u_char aap_flags; /* Flags (see below) */ + u_char aap_origin; /* Entry origin (see below) */ + u_char aap_age; /* Aging timeout (minutes) */ + Atm_addr aap_addr; /* ATM address */ + Atm_addr aap_subaddr; /* ATM subaddress */ +}; + +/* + * ARP entry flags + */ +#define ARPF_VALID 0x01 /* Entry is valid */ +#define ARPF_REFRESH 0x02 /* Entry has been refreshed */ + +/* + * ARP entry origin + */ +#define ARP_ORIG_PERM 50 /* Permanent entry */ + +/* + * IP VCC information + */ +struct air_ip_vcc_rsp { + struct sockaddr aip_dst_addr; /* Destination host */ + char aip_intf[IFNAMSIZ]; /* Interface name */ + u_short aip_vpi; /* VPI value */ + u_short aip_vci; /* VCI value */ + u_char aip_sig_proto; /* Signalling protocol */ + u_char aip_flags; /* Flags (IVF_*) */ + u_char aip_state; /* IP VCC state */ +}; + +/* + * ARP server information + */ +struct air_asrv_rsp { + char asp_intf[IFNAMSIZ]; /* Interface name */ + Atm_addr asp_addr; /* Server ATM address */ + Atm_addr asp_subaddr; /* Server ATM subaddress */ + int asp_state; /* Server state */ + int asp_nprefix; /* Number of prefix entries */ +}; + +/* + * Interface information + */ +struct air_int_rsp { + char anp_intf[IFNAMSIZ]; /* Interface name */ + Atm_addr anp_addr; /* ATM address */ + Atm_addr anp_subaddr; /* ATM subaddress */ + u_char anp_sig_proto; /* Signalling protocol */ + u_char anp_sig_state; /* Signalling protocol state */ + char anp_nif_pref[IFNAMSIZ]; /* Netif prefix */ + u_char anp_nif_cnt; /* No. of netifs */ +}; + +/* + * Network interface information + */ +struct air_netif_rsp { + char anp_intf[IFNAMSIZ]; /* Interface name */ + struct sockaddr anp_proto_addr; /* Protocol address */ + char anp_phy_intf[IFNAMSIZ]; /* Interface name */ +}; + +/* + * VCC information + */ +#define O_CNT 8 +struct air_vcc_rsp { + char avp_intf[IFNAMSIZ]; /* Interface name */ + u_short avp_vpi; /* VPI value */ + u_short avp_vci; /* VCI value */ + u_char avp_type; /* Type (SVC or PVC) */ + u_char avp_aal; /* AAL */ + u_char avp_sig_proto; /* Signalling protocol */ + Encaps_t avp_encaps; /* Encapsulation */ + u_char avp_state; /* State (sig mgr specific) */ + char avp_owners[(T_ATM_APP_NAME_LEN+1)*O_CNT];/* VCC users */ + Atm_addr avp_daddr; /* Address of far end */ + Atm_addr avp_dsubaddr; /* Subaddress of far end */ + long avp_ipdus; /* PDUs received from VCC */ + long avp_opdus; /* PDUs sent to VCC */ + long avp_ibytes; /* Bytes received from VCC */ + long avp_obytes; /* Bytes sent to VCC */ + long avp_ierrors; /* Errors receiving from VCC */ + long avp_oerrors; /* Errors sending to VCC */ + time_t avp_tstamp; /* State transition timestamp */ +}; + +/* + * Adapter configuration information + */ +struct air_cfg_rsp { + char acp_intf[IFNAMSIZ]; /* Interface name */ + Atm_config acp_cfg; /* Config info */ +}; +#define acp_vendor acp_cfg.ac_vendor +#define acp_vendapi acp_cfg.ac_vendapi +#define acp_device acp_cfg.ac_device +#define acp_media acp_cfg.ac_media +#define acp_serial acp_cfg.ac_serial +#define acp_bustype acp_cfg.ac_bustype +#define acp_busslot acp_cfg.ac_busslot +#define acp_ram acp_cfg.ac_ram +#define acp_ramsize acp_cfg.ac_ramsize +#define acp_macaddr acp_cfg.ac_macaddr +#define acp_hard_vers acp_cfg.ac_hard_vers +#define acp_firm_vers acp_cfg.ac_firm_vers + +/* + * Version information + */ +struct air_version_rsp { + int avp_version; /* Software version */ +}; + +/* + * Physical interface statistics + */ +struct air_phy_stat_rsp { + char app_intf[IFNAMSIZ]; /* Interface name */ + long app_ipdus; /* PDUs received from I/F */ + long app_opdus; /* PDUs sent to I/F */ + long app_ibytes; /* Bytes received from I/F */ + long app_obytes; /* Bytes sent to I/F */ + long app_ierrors; /* Errors receiving from I/F */ + long app_oerrors; /* Errors sending to I/F */ + long app_cmderrors; /* I/F command errors */ +}; + + +/* + * PF_ATM sub-operation codes + */ +#define AIOCS_CFG_ATT 1 +#define AIOCS_CFG_DET 2 +#define AIOCS_ADD_PVC 32 +#define AIOCS_ADD_ARP 33 +#define AIOCS_DEL_PVC 64 +#define AIOCS_DEL_SVC 65 +#define AIOCS_DEL_ARP 66 +#define AIOCS_SET_ASV 96 +#define AIOCS_SET_NIF 97 +#define AIOCS_SET_PRF 98 +#define AIOCS_SET_MAC 99 +#define AIOCS_INF_VST 160 +#define AIOCS_INF_IPM 161 +#define AIOCS_INF_ARP 162 +#define AIOCS_INF_ASV 163 +#define AIOCS_INF_INT 164 +#define AIOCS_INF_VCC 165 +#define AIOCS_INF_CFG 166 +#define AIOCS_INF_NIF 167 +#define AIOCS_INF_PIS 168 +#define AIOCS_INF_VER 169 + + +/* + * PF_ATM ioctls + */ +#if defined(sun) && !defined(__GNUC__) +#define AIOCCFG _IOW(A, 128, struct atmcfgreq) /* Configure i/f */ +#define AIOCADD _IOW(A, 129, struct atmaddreq) /* Add (e.g. PVC) */ +#define AIOCDEL _IOW(A, 130, struct atmdelreq) /* Delete */ +#define AIOCSET _IOW(A, 132, struct atmsetreq) /* Set (e.g. net i/f) */ +#define AIOCINFO _IOWR(A, 133, struct atminfreq) /* Show kernel info */ +#else +#define AIOCCFG _IOW('A', 128, struct atmcfgreq)/* Configure i/f */ +#define AIOCADD _IOW('A', 129, struct atmaddreq)/* Add (e.g. PVC) */ +#define AIOCDEL _IOW('A', 130, struct atmdelreq)/* Delete */ +#define AIOCSET _IOW('A', 132, struct atmsetreq)/* Set (e.g. net i/f) */ +#define AIOCINFO _IOWR('A', 133, struct atminfreq)/* Show kernel info */ +#endif + +#endif /* _NETATM_ATM_IOCTL_H */ diff --git a/sys/netatm/atm_pcb.h b/sys/netatm/atm_pcb.h new file mode 100644 index 0000000..12ac5d0 --- /dev/null +++ b/sys/netatm/atm_pcb.h @@ -0,0 +1,92 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_pcb.h,v 1.2 1998/07/30 22:30:51 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * ATM socket protocol definitions + * + */ + +#ifndef _NETATM_ATM_PCB_H +#define _NETATM_ATM_PCB_H + + +#ifdef ATM_KERNEL +/* + * ATM Socket PCB + * + * Common structure for all ATM protocol sockets. This control block + * will be used for all ATM socket types. + */ +struct atm_pcb { + struct socket *atp_socket; /* Socket */ + Atm_connection *atp_conn; /* Connection manager token */ + u_char atp_type; /* Protocol type (see below) */ + u_char atp_flags; /* Protocol flags (see below) */ + Atm_attributes atp_attr; /* Socket's call attributes */ + char atp_name[T_ATM_APP_NAME_LEN]; /* Owner's name */ +}; +typedef struct atm_pcb Atm_pcb; + +/* + * Protocol Types + */ +#define ATPT_AAL5 0 /* AAL type 5 protocol */ +#define ATPT_SSCOP 1 /* SSCOP protocol */ +#define ATPT_NUM 2 /* Number of protocols */ + +/* + * PCB Flags + */ + + +/* + * Handy macros + */ +#define sotoatmpcb(so) ((Atm_pcb *)(so)->so_pcb) + + +/* + * ATM Socket Statistics + */ +struct atm_sock_stat { + u_long as_connreq[ATPT_NUM]; /* Connection requests */ + u_long as_inconn[ATPT_NUM]; /* Incoming connection requests */ + u_long as_conncomp[ATPT_NUM]; /* Connections completed */ + u_long as_connfail[ATPT_NUM]; /* Connections failed */ + u_long as_connrel[ATPT_NUM]; /* Connections released */ + u_long as_connclr[ATPT_NUM]; /* Connections cleared */ + u_long as_indrop[ATPT_NUM]; /* Input packets dropped */ + u_long as_outdrop[ATPT_NUM]; /* Output packets dropped */ +}; +#endif /* ATM_KERNEL */ + +#endif /* _NETATM_ATM_PCB_H */ diff --git a/sys/netatm/atm_proto.c b/sys/netatm/atm_proto.c new file mode 100644 index 0000000..ddd1a88 --- /dev/null +++ b/sys/netatm/atm_proto.c @@ -0,0 +1,205 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_proto.c,v 1.6 1998/02/19 19:52:06 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * ATM socket protocol family support definitions + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_proto.c,v 1.6 1998/02/19 19:52:06 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + + +struct protosw atmsw[] = { +{ SOCK_DGRAM, /* ioctl()-only */ + &atmdomain, + 0, + 0, + 0, /* pr_input */ + 0, /* pr_output */ + 0, /* pr_ctlinput */ + 0, /* pr_ctloutput */ + 0, /* pr_ousrreq */ + 0, /* pr_init */ + 0, /* pr_fasttimo */ + 0, /* pr_slowtimo */ + 0, /* pr_drain */ + &atm_dgram_usrreqs, /* pr_usrreqs */ +}, + +{ SOCK_SEQPACKET, /* AAL-5 */ + &atmdomain, + ATM_PROTO_AAL5, + PR_ATOMIC|PR_CONNREQUIRED, + 0, /* pr_input */ + 0, /* pr_output */ + 0, /* pr_ctlinput */ + atm_aal5_ctloutput, /* pr_ctloutput */ + 0, /* pr_ousrreq */ + 0, /* pr_init */ + 0, /* pr_fasttimo */ + 0, /* pr_slowtimo */ + 0, /* pr_drain */ + &atm_aal5_usrreqs, /* pr_usrreqs */ +}, + +#ifdef XXX +{ SOCK_SEQPACKET, /* SSCOP */ + &atmdomain, + ATM_PROTO_SSCOP, + PR_ATOMIC|PR_CONNREQUIRED|PR_WANTRCVD, + x, /* pr_input */ + x, /* pr_output */ + x, /* pr_ctlinput */ + x, /* pr_ctloutput */ + 0, /* pr_ousrreq */ + 0, /* pr_init */ + 0, /* pr_fasttimo */ + 0, /* pr_slowtimo */ + x, /* pr_drain */ + x, /* pr_usrreqs */ +}, +#endif +}; + +struct domain atmdomain = { + AF_ATM, + "atm", +#if defined(__FreeBSD__) + atm_initialize, +#else + 0, +#endif + 0, + 0, + atmsw, + &atmsw[sizeof(atmsw) / sizeof(atmsw[0])] +}; + +#ifdef __FreeBSD__ +DOMAIN_SET(atm); +#endif + + +#if (defined(__FreeBSD__) && (BSD >= 199506)) +/* + * Protocol request not supported + * + * Arguments: + * so pointer to socket + * + * Returns: + * errno error - operation not supported + * + */ +int +atm_proto_notsupp1(so) + struct socket *so; +{ + return (EOPNOTSUPP); +} + + +/* + * Protocol request not supported + * + * Arguments: + * so pointer to socket + * addr pointer to protocol address + * p pointer to process + * + * Returns: + * errno error - operation not supported + * + */ +int +atm_proto_notsupp2(so, addr, p) + struct socket *so; + struct sockaddr *addr; + struct proc *p; +{ + return (EOPNOTSUPP); +} + + +/* + * Protocol request not supported + * + * Arguments: + * so pointer to socket + * addr pointer to pointer to protocol address + * + * Returns: + * errno error - operation not supported + * + */ +int +atm_proto_notsupp3(so, addr) + struct socket *so; + struct sockaddr **addr; +{ + return (EOPNOTSUPP); +} + + +/* + * Protocol request not supported + * + * Arguments: + * so pointer to socket + * i integer + * m pointer to kernel buffer + * addr pointer to protocol address + * m2 pointer to kernel buffer + * p pointer to process + * + * Returns: + * errno error - operation not supported + * + */ +int +atm_proto_notsupp4(so, i, m, addr, m2, p) + struct socket *so; + int i; + KBuffer *m; + struct sockaddr *addr; + KBuffer *m2; + struct proc *p; +{ + return (EOPNOTSUPP); +} + +#endif /* (defined(__FreeBSD__) && (BSD >= 199506)) */ + diff --git a/sys/netatm/atm_sap.h b/sys/netatm/atm_sap.h new file mode 100644 index 0000000..1386516 --- /dev/null +++ b/sys/netatm/atm_sap.h @@ -0,0 +1,81 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_sap.h,v 1.3 1998/02/19 19:59:38 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * ATM Services definitions + * + */ + +#ifndef _NETATM_ATM_SAP_H +#define _NETATM_ATM_SAP_H + +/* + * Service Access Point (SAP) + * + * A SAP specifies the definition of an interface used between two adjacent + * layers. The SAP is named for the services the lower layer provides to + * the upper layer. + * + * The types of SAPs used are: + * Stack - defines the interfaces between stack service entities. + * These are further divided into: + * + * Stack class SAP - which identifies the type of interface + * used. All SAPs of a particular class will provide + * the same interface services to the higher layer. + * All stack command codes are constructed using class + * SAP values. + * + * Stack instance SAP - which identifies the specific identity + * of the layer providing the class interface. + */ +typedef u_short Sap_t; + +#define SAP_TYPE_MASK 0xc000 +#define SAP_TYPE_STACK 0x8000 +#define SAP_CLASS_MASK 0xff80 + +#define SAP_STACK(c, i) (SAP_TYPE_STACK | ((c) << 7) | (i)) + +/* Stack SAPs */ +#define SAP_ATM SAP_STACK(1, 0) /* ATM cell */ +#define SAP_SAR SAP_STACK(2, 0) /* AAL SAR */ +#define SAP_SAR_AAL3_4 SAP_STACK(2, 3) /* AAL3/4 SAR */ +#define SAP_SAR_AAL5 SAP_STACK(2, 5) /* AAL5 SAR */ +#define SAP_CPCS SAP_STACK(3, 0) /* AAL CPCS */ +#define SAP_CPCS_AAL3_4 SAP_STACK(3, 3) /* AAL3/4 CPCS */ +#define SAP_CPCS_AAL5 SAP_STACK(3, 5) /* AAL5 CPCS */ +#define SAP_SSCOP SAP_STACK(4, 0) /* ITU Q.2110 */ +#define SAP_SSCF_UNI SAP_STACK(5, 0) /* ITU Q.2130 */ +#define SAP_SSCF_NNI SAP_STACK(6, 0) /* ITU Q.2140 */ + +#endif /* _NETATM_ATM_SAP_H */ diff --git a/sys/netatm/atm_sigmgr.h b/sys/netatm/atm_sigmgr.h new file mode 100644 index 0000000..1b9388e --- /dev/null +++ b/sys/netatm/atm_sigmgr.h @@ -0,0 +1,109 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_sigmgr.h,v 1.7 1998/03/24 20:43:59 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * ATM Signalling Manager definitions + * + */ + +#ifndef _NETATM_ATM_SIGMGR_H +#define _NETATM_ATM_SIGMGR_H + +#ifdef ATM_KERNEL +/* + * Structure common to all ATM Signalling Managers. Each Signalling + * Manager must create one of these and use it to register itself + * with the system. + */ +struct sigmgr { + struct sigmgr *sm_next; /* Next registered sigmgr */ + u_char sm_proto; /* Signalling protocol (see below) */ + struct siginst *sm_prinst; /* List of protocol instances */ +/* Exported functions */ + int (*sm_attach) /* Attach interface */ + __P((struct sigmgr *, struct atm_pif *)); + int (*sm_detach) /* Detach interface */ + __P((struct atm_pif *)); + int (*sm_setup) /* Connection setup */ + __P((Atm_connvc *, int *)); + int (*sm_accept) /* Call accepted */ + __P((struct vccb *, int *)); + int (*sm_reject) /* Call rejected */ + __P((struct vccb *, int *)); + int (*sm_release) /* Connection release */ + __P((struct vccb *, int *)); + int (*sm_free) /* Free connection resources */ + __P((struct vccb *)); + int (*sm_ioctl) /* Ioctl handler */ + __P((int, caddr_t, caddr_t)); +}; +#endif /* ATM_KERNEL */ + +/* + * ATM Signalling Protocols + */ +#define ATM_SIG_PVC 1 /* PVC-only */ +#define ATM_SIG_SPANS 2 /* Fore Systems SPANS */ +#define ATM_SIG_UNI30 3 /* ATM Forum UNI 3.0 */ +#define ATM_SIG_UNI31 4 /* ATM Forum UNI 3.1 */ +#define ATM_SIG_UNI40 5 /* ATM Forum UNI 4.0 */ + + +#ifdef ATM_KERNEL +/* + * Signalling Protocol Instance control block header. Common header for + * every signalling protocol instance control block. + */ +struct siginst { + struct siginst *si_next; /* Next sigmgr protocol instance */ + struct atm_pif *si_pif; /* Device interface */ + Atm_addr si_addr; /* Interface ATM address */ + Atm_addr si_subaddr; /* Interface ATM subaddress */ + Queue_t si_vccq; /* VCCB queue */ + u_short si_state; /* Protocol state (sigmgr specific) */ + +/* Exported protocol services */ + struct ip_serv *si_ipserv; /* IP/ATM services */ +}; + + +/* + * Sigmgr function return codes + */ +#define CALL_PROCEEDING 1 /* Connection request is in progress */ +#define CALL_FAILED 2 /* Connection request failed */ +#define CALL_CONNECTED 3 /* Connection setup successful */ +#define CALL_CLEARED 4 /* Connection has been terminated */ + +#endif /* ATM_KERNEL */ + +#endif /* _NETATM_ATM_SIGMGR_H */ diff --git a/sys/netatm/atm_signal.c b/sys/netatm/atm_signal.c new file mode 100644 index 0000000..8acbf7a --- /dev/null +++ b/sys/netatm/atm_signal.c @@ -0,0 +1,512 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_signal.c,v 1.8 1998/03/24 20:45:37 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * General ATM signalling management + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_signal.c,v 1.8 1998/03/24 20:45:37 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + + +/* + * Local variables + */ +static struct sigmgr *atm_sigmgr_head = NULL; +static struct stack_defn *atm_stack_head = NULL; + + +/* + * Register a new Signalling Manager + * + * Each Signalling Manager must register itself here upon completing + * its internal initialization. This applies to both linked and loaded + * managers. + * + * Arguments: + * smp pointer to Signalling Manager description + * + * Returns: + * 0 registration was successful + * errno registration failed - reason indicated + * + */ +int +atm_sigmgr_register(smp) + struct sigmgr *smp; +{ + struct sigmgr *smp2; + int s = splnet(); + + /* + * See if we need to be initialized + */ + if (!atm_init) + atm_initialize(); + + /* + * Make sure there's only one instance of each protocol + */ + for (smp2 = atm_sigmgr_head; smp2 != NULL; smp2 = smp2->sm_next) { + if (smp->sm_proto == smp2->sm_proto) { + (void) splx(s); + return (EEXIST); + } + } + + /* + * Looks okay, link it in + */ + LINK2TAIL(smp, struct sigmgr, atm_sigmgr_head, sm_next); + + (void) splx(s); + return (0); +} + + +/* + * De-register a Signalling Manager + * + * Each Signalling Manager must de-register (is this really a word?) + * itself before removing itself from the system. This really only + * applies to managers about to be modunload'ed. It is the signal + * manager's responsibility to ensure that all its protocol instances + * have been successfully terminated before de-registering itself. + * + * Arguments: + * smp pointer to Signalling Manager description + * + * Returns: + * 0 deregistration was successful + * errno deregistration failed - reason indicated + * + */ +int +atm_sigmgr_deregister(smp) + struct sigmgr *smp; +{ + int found, s = splnet(); + + /* + * Unlink descriptor + */ + UNLINKF(smp, struct sigmgr, atm_sigmgr_head, sm_next, found); + + (void) splx(s); + + if (!found) + return (ENOENT); + + return (0); +} + + +/* + * Attach a Signalling Manager to an ATM physical interface + * + * Each ATM physical interface must have a signalling manager attached to + * itself for the signalling protocol to be run across this interface. The + * interface must be registered and completely initialized before the attach, + * since the signalling manager may initiate virtual circuit activity as part + * its response to this call. + * + * Called at splnet. + * + * Arguments: + * pip pointer to atm physical interface control block + * proto requested signalling protocol + * + * Returns: + * 0 attach successful + * errno attach failed - reason indicated + * + */ +int +atm_sigmgr_attach(pip, proto) + struct atm_pif *pip; + u_char proto; +{ + struct atm_pif *tp; + struct sigmgr *smp; + int err; + + /* + * Make sure interface is registered + */ + for (tp = atm_interface_head; tp != NULL; tp = tp->pif_next) { + if (tp == pip) + break; + } + if (tp == NULL) { + return (ENOENT); + } + + /* + * Make sure no signalling manager is already attached + */ + if (pip->pif_sigmgr != NULL) { + return (EEXIST); + } + + /* + * Must have at least one network interface defined + */ + if (pip->pif_nif == NULL) + return (ETOOMANYREFS); + + /* + * Find requested protocol + */ + for (smp = atm_sigmgr_head; smp != NULL; smp = smp->sm_next) { + if (smp->sm_proto == proto) + break; + } + if (smp == NULL) { + return (EPROTONOSUPPORT); + } + + /* + * Tell the signal manager about it + */ + err = (*smp->sm_attach)(smp, pip); + + /* + * Tell all registered convergence modules about this + */ + if (!err) { + struct atm_nif *nip; + struct atm_ncm *ncp; + + for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) { + for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) { + if (err = (*ncp->ncm_stat) + (NCM_SIGATTACH, nip, 0)) + break; + } + if (err) + break; + } + + if (err) { + /* + * Someone's unhappy, so back all this out + */ + (void) atm_sigmgr_detach(pip); + } + } + + return (err); +} + + +/* + * Detach an ATM physical interface from a Signalling Manager + * + * The ATM interface must be detached from the signalling manager + * before the interface can be de-registered. + * + * Called at splnet. + * + * Arguments: + * pip pointer to atm physical interface control block + * + * Returns: + * 0 detach successful + * errno detach failed - reason indicated + * + */ +int +atm_sigmgr_detach(pip) + struct atm_pif *pip; +{ + struct atm_pif *tp; + struct atm_nif *nip; + struct atm_ncm *ncp; + int err; + + + /* + * Make sure interface is registered + */ + for (tp = atm_interface_head; tp != NULL; tp = tp->pif_next) { + if (tp == pip) + break; + } + if (tp == NULL) { + return (ENOENT); + } + + /* + * Make sure a signalling manager is attached + */ + if (pip->pif_sigmgr == NULL) { + return (ENOENT); + } + + /* + * Tell all registered convergence modules about this + */ + for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) { + for (ncp = atm_netconv_head; ncp; ncp = ncp->ncm_next) { + (void) (*ncp->ncm_stat)(NCM_SIGDETACH, nip, 0); + } + } + + /* + * Tell the signal manager about it + * + * NOTE: + * The only reason this should ever fail is if things are really + * hosed up somewhere, in which case doing a bunch of NCM_SIGATTACH's + * here just doesn't seem to help much. + */ + err = (*pip->pif_sigmgr->sm_detach)(pip); + + return (err); +} + + +/* + * Register an ATM Stack Service + * + * Each ATM stack service provider must register its provided service(s) here. + * Each service must be registered separately. Service providers include + * both loaded and linked kernel modules. Device driver services are NOT + * registered here - their service registry is performed implicitly through + * the device interface structure stack services list (pif_services). + * + * Arguments: + * sdp pointer to stack service definition block + * + * Returns: + * 0 registration successful + * errno registration failed - reason indicated + * + */ +int +atm_stack_register(sdp) + struct stack_defn *sdp; +{ + struct stack_defn *tdp; + int s = splnet(); + + /* + * See if we need to be initialized + */ + if (!atm_init) + atm_initialize(); + + /* + * Ensure no duplicates + */ + for (tdp = atm_stack_head; tdp != NULL; tdp = tdp->sd_next) { + if (tdp->sd_sap == sdp->sd_sap) + break; + } + if (tdp != NULL) { + (void) splx(s); + return (EEXIST); + } + + /* + * Add stack to list + */ + LINK2TAIL(sdp, struct stack_defn, atm_stack_head, sd_next); + + (void) splx(s); + return (0); +} + + +/* + * De-register an ATM Stack Service + * + * Each ATM stack service provider must de-register its registered service(s) + * before terminating the service. Specifically, loaded kernel modules + * must de-register their services before unloading themselves. + * + * Arguments: + * sdp pointer to stack service definition block + * + * Returns: + * 0 de-registration successful + * errno de-registration failed - reason indicated + * + */ +int +atm_stack_deregister(sdp) + struct stack_defn *sdp; +{ + int found, s = splnet(); + + /* + * Remove service from list + */ + UNLINKF(sdp, struct stack_defn, atm_stack_head, sd_next, found); + (void) splx(s); + + if (!found) + return (ENOENT); + + return (0); +} + + +/* + * Create and Instantiate a Stack + * + * For the requested stack list, locate the stack service definitions + * necessary to build the stack to implement the listed services. + * The stack service definitions provided by the interface device-driver + * are always preferred, since they are (hopefully) done with + * hardware assistance from the interface card. + * + * After the stack has been built, the selected services are called to + * notify them of the new stack instantiation. Each service should then + * allocate all the resources it requires for this new stack instance. + * The service should then wait for subsequent protocol notification + * via its stack command handlers. + * + * Must be called at splnet. + * + * Arguments: + * cvp pointer to connection vcc block for the created stack + * tlp pointer to stack list + * upf top-of-stack CM upper command handler + * + * Returns: + * 0 stack successfully created + * errno failed - reason indicated + * + */ +int +atm_create_stack(cvp, tlp, upf) + Atm_connvc *cvp; + struct stack_list *tlp; + void (*upf)__P((int, void *, int, int)); +{ + struct stack_defn *sdp, usd; + struct stack_inst svs; + struct atm_pif *pip = cvp->cvc_attr.nif->nif_pif; + int i, err; + + + /* + * Initialize stack (element 0 is for owner's services) + */ + svs.si_srvc[1] = sdp = NULL; + + /* + * Locate service provider for each service in the + * stack list. We prefer interface driver providers + * over kernel module providers. + */ + for (i = 0; i < STACK_CNT; i++) { + Sap_t sap; + + /* Stack list is 0-terminated */ + if ((sap = tlp->sl_sap[i]) == 0) + break; + + /* + * Search interface's services + */ + for (sdp = pip->pif_services; sdp; sdp = sdp->sd_next) + if (sdp->sd_sap == sap) + break; + if (sdp == NULL) { + + /* + * Search kernel services + */ + for (sdp = atm_stack_head; sdp; + sdp = sdp->sd_next) + if (sdp->sd_sap == sap) + break; + } + if (sdp == NULL) { + + /* + * Requested service id not found + */ + return (ENOENT); + } + + /* + * Save stack definition for this service + */ + svs.si_srvc[i+1] = sdp; + + /* + * Quit loop if this service is terminal, ie. if + * it takes care of the rest of the stack. + */ + if (sdp->sd_flag & SDF_TERM) + break; + } + + /* + * Ensure stack instance array is located and terminated + */ + if ((svs.si_srvc[1] == NULL) || !(sdp->sd_flag & SDF_TERM)) { + return (ENOENT); + } + + /* + * Setup owner service definition + */ + KM_ZERO((caddr_t)&usd, sizeof(struct stack_defn)); + usd.sd_upper = upf; + usd.sd_toku = cvp; + svs.si_srvc[0] = &usd; + + /* + * Instantiate the stack + */ + err = (*svs.si_srvc[1]->sd_inst)(&svs.si_srvc[0], cvp); + if (err) { + return (err); + } + + /* + * Save top 'o stack info + */ + cvp->cvc_lower = svs.si_srvc[1]->sd_lower; + cvp->cvc_tokl = svs.si_srvc[1]->sd_toku; + + return (0); +} + diff --git a/sys/netatm/atm_socket.c b/sys/netatm/atm_socket.c new file mode 100644 index 0000000..2370a15 --- /dev/null +++ b/sys/netatm/atm_socket.c @@ -0,0 +1,1311 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_socket.c,v 1.3 1998/07/30 22:30:53 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * ATM common socket protocol processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_socket.c,v 1.3 1998/07/30 22:30:53 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + + +/* + * Local functions + */ + + +/* + * Local variables + */ +static struct sp_info atm_pcb_pool = { + "atm pcb pool", /* si_name */ + sizeof(Atm_pcb), /* si_blksiz */ + 10, /* si_blkcnt */ + 100 /* si_maxallow */ +}; + +static struct t_atm_cause atm_sock_cause = { + T_ATM_ITU_CODING, + T_ATM_LOC_USER, + T_ATM_CAUSE_UNSPECIFIED_NORMAL, + {0, 0, 0, 0} +}; + + +/* + * Allocate resources for a new ATM socket + * + * Called at splnet. + * + * Arguments: + * so pointer to socket + * send socket send buffer maximum + * recv socket receive buffer maximum + * + * Returns: + * 0 attach successful + * errno attach failed - reason indicated + * + */ +int +atm_sock_attach(so, send, recv) + struct socket *so; + u_long send; + u_long recv; +{ + Atm_pcb *atp = sotoatmpcb(so); + int err; + + /* + * Make sure initialization has happened + */ + if (!atm_init) + atm_initialize(); + + /* + * Make sure we're not already attached + */ + if (atp) + return (EISCONN); + + /* + * Reserve socket buffer space, if not already done + */ + if ((so->so_snd.sb_hiwat == 0) || (so->so_rcv.sb_hiwat == 0)) { + err = soreserve(so, send, recv); + if (err) + return (err); + } + + /* + * Allocate and initialize our control block + */ + atp = (Atm_pcb *)atm_allocate(&atm_pcb_pool); + if (atp == NULL) + return (ENOMEM); + + atp->atp_socket = so; + so->so_pcb = (caddr_t)atp; + return (0); +} + + +/* + * Detach from socket and free resources + * + * Called at splnet. + * + * Arguments: + * so pointer to socket + * + * Returns: + * 0 detach successful + * errno detach failed - reason indicated + * + */ +int +atm_sock_detach(so) + struct socket *so; +{ + Atm_pcb *atp = sotoatmpcb(so); + + /* + * Make sure we're still attached + */ + if (atp == NULL) + return (ENOTCONN); + + /* + * Terminate any (possibly pending) connection + */ + if (atp->atp_conn) { + (void) atm_sock_disconnect(so); + } + + /* + * Break links and free control blocks + */ + so->so_pcb = NULL; + sofree(so); + + atm_free((caddr_t)atp); + + return (0); +} + + +/* + * Bind local address to socket + * + * Called at splnet. + * + * Arguments: + * so pointer to socket + * addr pointer to protocol address + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +int +atm_sock_bind(so, addr) + struct socket *so; + struct sockaddr *addr; +{ + Atm_pcb *atp = sotoatmpcb(so); + Atm_attributes attr; + struct sockaddr_atm *satm; + struct t_atm_sap_addr *sapadr; + struct t_atm_sap_layer2 *sapl2; + struct t_atm_sap_layer3 *sapl3; + struct t_atm_sap_appl *sapapl; + + /* + * Make sure we're still attached + */ + if (atp == NULL) + return (ENOTCONN); + + /* + * Can't change local address once we've started connection process + */ + if (atp->atp_conn != NULL) + return (EADDRNOTAVAIL); + + /* + * Validate requested local address + */ + satm = (struct sockaddr_atm *)addr; + if (satm->satm_family != AF_ATM) + return (EAFNOSUPPORT); + + sapadr = &satm->satm_addr.t_atm_sap_addr; + if (sapadr->SVE_tag_addr == T_ATM_PRESENT) { + if (sapadr->address_format == T_ATM_ENDSYS_ADDR) { + if (sapadr->SVE_tag_selector != T_ATM_PRESENT) + return (EINVAL); + } else if (sapadr->address_format == T_ATM_E164_ADDR) { + if (sapadr->SVE_tag_selector != T_ATM_ABSENT) + return (EINVAL); + } else + return (EINVAL); + } else if ((sapadr->SVE_tag_addr != T_ATM_ABSENT) && + (sapadr->SVE_tag_addr != T_ATM_ANY)) + return (EINVAL); + if (sapadr->address_length > ATM_ADDR_LEN) + return (EINVAL); + + sapl2 = &satm->satm_addr.t_atm_sap_layer2; + if (sapl2->SVE_tag == T_ATM_PRESENT) { + if ((sapl2->ID_type != T_ATM_SIMPLE_ID) && + (sapl2->ID_type != T_ATM_USER_ID)) + return (EINVAL); + } else if ((sapl2->SVE_tag != T_ATM_ABSENT) && + (sapl2->SVE_tag != T_ATM_ANY)) + return (EINVAL); + + sapl3 = &satm->satm_addr.t_atm_sap_layer3; + if (sapl3->SVE_tag == T_ATM_PRESENT) { + if ((sapl3->ID_type != T_ATM_SIMPLE_ID) && + (sapl3->ID_type != T_ATM_IPI_ID) && + (sapl3->ID_type != T_ATM_SNAP_ID) && + (sapl3->ID_type != T_ATM_USER_ID)) + return (EINVAL); + } else if ((sapl3->SVE_tag != T_ATM_ABSENT) && + (sapl3->SVE_tag != T_ATM_ANY)) + return (EINVAL); + + sapapl = &satm->satm_addr.t_atm_sap_appl; + if (sapapl->SVE_tag == T_ATM_PRESENT) { + if ((sapapl->ID_type != T_ATM_ISO_APP_ID) && + (sapapl->ID_type != T_ATM_USER_APP_ID) && + (sapapl->ID_type != T_ATM_VENDOR_APP_ID)) + return (EINVAL); + } else if ((sapapl->SVE_tag != T_ATM_ABSENT) && + (sapapl->SVE_tag != T_ATM_ANY)) + return (EINVAL); + + /* + * Create temporary attributes list so that we can check out the + * new bind parameters before we modify the socket's values; + */ + attr = atp->atp_attr; + attr.called.tag = sapadr->SVE_tag_addr; + KM_COPY(&sapadr->address_format, &attr.called.addr, sizeof(Atm_addr)); + + attr.blli.tag_l2 = sapl2->SVE_tag; + if (sapl2->SVE_tag == T_ATM_PRESENT) { + attr.blli.v.layer_2_protocol.ID_type = sapl2->ID_type; + KM_COPY(&sapl2->ID, &attr.blli.v.layer_2_protocol.ID, + sizeof(attr.blli.v.layer_2_protocol.ID)); + } + + attr.blli.tag_l3 = sapl3->SVE_tag; + if (sapl3->SVE_tag == T_ATM_PRESENT) { + attr.blli.v.layer_3_protocol.ID_type = sapl3->ID_type; + KM_COPY(&sapl3->ID, &attr.blli.v.layer_3_protocol.ID, + sizeof(attr.blli.v.layer_3_protocol.ID)); + } + + attr.bhli.tag = sapapl->SVE_tag; + if (sapapl->SVE_tag == T_ATM_PRESENT) { + attr.bhli.v.ID_type = sapapl->ID_type; + KM_COPY(&sapapl->ID, &attr.bhli.v.ID, + sizeof(attr.bhli.v.ID)); + } + + /* + * Make sure we have unique listening attributes + */ + if (atm_cm_match(&attr, NULL) != NULL) + return (EADDRINUSE); + + /* + * Looks good, save new attributes + */ + atp->atp_attr = attr; + + return (0); +} + + +/* + * Listen for incoming connections + * + * Called at splnet. + * + * Arguments: + * so pointer to socket + * epp pointer to endpoint definition structure + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +int +atm_sock_listen(so, epp) + struct socket *so; + Atm_endpoint *epp; +{ + Atm_pcb *atp = sotoatmpcb(so); + + /* + * Make sure we're still attached + */ + if (atp == NULL) + return (ENOTCONN); + + /* + * Start listening for incoming calls + */ + return (atm_cm_listen(epp, atp, &atp->atp_attr, &atp->atp_conn)); +} + + +/* + * Connect socket to peer + * + * Called at splnet. + * + * Arguments: + * so pointer to socket + * addr pointer to protocol address + * epp pointer to endpoint definition structure + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +int +atm_sock_connect(so, addr, epp) + struct socket *so; + struct sockaddr *addr; + Atm_endpoint *epp; +{ + Atm_pcb *atp = sotoatmpcb(so); + struct sockaddr_atm *satm; + struct t_atm_sap_addr *sapadr; + struct t_atm_sap_layer2 *sapl2; + struct t_atm_sap_layer3 *sapl3; + struct t_atm_sap_appl *sapapl; + int err; + + /* + * Make sure we're still attached + */ + if (atp == NULL) + return (ENOTCONN); + + /* + * Validate requested peer address + */ + satm = (struct sockaddr_atm *)addr; + if (satm->satm_family != AF_ATM) + return (EAFNOSUPPORT); + + sapadr = &satm->satm_addr.t_atm_sap_addr; + if (sapadr->SVE_tag_addr != T_ATM_PRESENT) + return (EINVAL); + if (sapadr->address_format == T_ATM_ENDSYS_ADDR) { + if (sapadr->SVE_tag_selector != T_ATM_PRESENT) + return (EINVAL); + } else if (sapadr->address_format == T_ATM_E164_ADDR) { + if (sapadr->SVE_tag_selector != T_ATM_ABSENT) + return (EINVAL); + } else if (sapadr->address_format == T_ATM_PVC_ADDR) { + if (sapadr->SVE_tag_selector != T_ATM_ABSENT) + return (EINVAL); + } else + return (EINVAL); + if (sapadr->address_length > ATM_ADDR_LEN) + return (EINVAL); + + sapl2 = &satm->satm_addr.t_atm_sap_layer2; + if (sapl2->SVE_tag == T_ATM_PRESENT) { + if ((sapl2->ID_type != T_ATM_SIMPLE_ID) && + (sapl2->ID_type != T_ATM_USER_ID)) + return (EINVAL); + } else if (sapl2->SVE_tag != T_ATM_ABSENT) + return (EINVAL); + + sapl3 = &satm->satm_addr.t_atm_sap_layer3; + if (sapl3->SVE_tag == T_ATM_PRESENT) { + if ((sapl3->ID_type != T_ATM_SIMPLE_ID) && + (sapl3->ID_type != T_ATM_IPI_ID) && + (sapl3->ID_type != T_ATM_SNAP_ID) && + (sapl3->ID_type != T_ATM_USER_ID)) + return (EINVAL); + } else if (sapl3->SVE_tag != T_ATM_ABSENT) + return (EINVAL); + + sapapl = &satm->satm_addr.t_atm_sap_appl; + if (sapapl->SVE_tag == T_ATM_PRESENT) { + if ((sapapl->ID_type != T_ATM_ISO_APP_ID) && + (sapapl->ID_type != T_ATM_USER_APP_ID) && + (sapapl->ID_type != T_ATM_VENDOR_APP_ID)) + return (EINVAL); + } else if (sapapl->SVE_tag != T_ATM_ABSENT) + return (EINVAL); + + /* + * Select an outgoing network interface + */ + if (atp->atp_attr.nif == NULL) { + struct atm_pif *pip; + + for (pip = atm_interface_head; pip != NULL; + pip = pip->pif_next) { + if (pip->pif_nif != NULL) { + atp->atp_attr.nif = pip->pif_nif; + break; + } + } + if (atp->atp_attr.nif == NULL) + return (ENXIO); + } + + /* + * Set supplied connection attributes + */ + atp->atp_attr.called.tag = T_ATM_PRESENT; + KM_COPY(&sapadr->address_format, &atp->atp_attr.called.addr, + sizeof(Atm_addr)); + + atp->atp_attr.blli.tag_l2 = sapl2->SVE_tag; + if (sapl2->SVE_tag == T_ATM_PRESENT) { + atp->atp_attr.blli.v.layer_2_protocol.ID_type = sapl2->ID_type; + KM_COPY(&sapl2->ID, &atp->atp_attr.blli.v.layer_2_protocol.ID, + sizeof(atp->atp_attr.blli.v.layer_2_protocol.ID)); + } + + atp->atp_attr.blli.tag_l3 = sapl3->SVE_tag; + if (sapl3->SVE_tag == T_ATM_PRESENT) { + atp->atp_attr.blli.v.layer_3_protocol.ID_type = sapl3->ID_type; + KM_COPY(&sapl3->ID, &atp->atp_attr.blli.v.layer_3_protocol.ID, + sizeof(atp->atp_attr.blli.v.layer_3_protocol.ID)); + } + + atp->atp_attr.bhli.tag = sapapl->SVE_tag; + if (sapapl->SVE_tag == T_ATM_PRESENT) { + atp->atp_attr.bhli.v.ID_type = sapapl->ID_type; + KM_COPY(&sapapl->ID, &atp->atp_attr.bhli.v.ID, + sizeof(atp->atp_attr.bhli.v.ID)); + } + + /* + * We're finally ready to initiate the ATM connection + */ + soisconnecting(so); + atm_sock_stat.as_connreq[atp->atp_type]++; + err = atm_cm_connect(epp, atp, &atp->atp_attr, &atp->atp_conn); + if (err == 0) { + /* + * Connection is setup + */ + atm_sock_stat.as_conncomp[atp->atp_type]++; + soisconnected(so); + + } else if (err == EINPROGRESS) { + /* + * We've got to wait for a connected event + */ + err = 0; + + } else { + /* + * Call failed... + */ + atm_sock_stat.as_connfail[atp->atp_type]++; + soisdisconnected(so); + } + + return (err); +} + + +/* + * Disconnect connected socket + * + * Called at splnet. + * + * Arguments: + * so pointer to socket + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +int +atm_sock_disconnect(so) + struct socket *so; +{ + Atm_pcb *atp = sotoatmpcb(so); + struct t_atm_cause *cause; + int err; + + /* + * Make sure we're still attached + */ + if (atp == NULL) + return (ENOTCONN); + + /* + * Release the ATM connection + */ + if (atp->atp_conn) { + if (atp->atp_attr.cause.tag == T_ATM_PRESENT) + cause = &atp->atp_attr.cause.v; + else + cause = &atm_sock_cause; + err = atm_cm_release(atp->atp_conn, cause); + if (err) + log(LOG_ERR, "atm_sock_disconnect: release fail (%d)\n", + err); + atm_sock_stat.as_connrel[atp->atp_type]++; + atp->atp_conn = NULL; + } + + soisdisconnected(so); + + return (0); +} + + +/* + * Retrieve local socket address + * + * Called at splnet. + * + * Arguments: + * so pointer to socket + * addr pointer to pointer to contain protocol address + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +int +atm_sock_sockaddr(so, addr) + struct socket *so; + struct sockaddr **addr; +{ + struct sockaddr_atm *satm; + struct t_atm_sap_addr *saddr; + Atm_pcb *atp = sotoatmpcb(so); + + /* + * Return local interface address, if known + */ + satm = KM_ALLOC(sizeof *satm, M_SONAME, M_WAITOK); + if (satm == NULL) + return (ENOMEM); + + KM_ZERO(satm, sizeof(*satm)); + satm->satm_family = AF_ATM; +#if (defined(BSD) && (BSD >= 199103)) + satm->satm_len = sizeof(*satm); +#endif + + saddr = &satm->satm_addr.t_atm_sap_addr; + if (atp->atp_attr.nif && atp->atp_attr.nif->nif_pif->pif_siginst) { + saddr->SVE_tag_addr = T_ATM_PRESENT; + ATM_ADDR_SEL_COPY( + &atp->atp_attr.nif->nif_pif->pif_siginst->si_addr, + atp->atp_attr.nif->nif_sel, saddr); + if (saddr->address_format == T_ATM_ENDSYS_ADDR) + saddr->SVE_tag_selector = T_ATM_PRESENT; + else + saddr->SVE_tag_selector = T_ATM_ABSENT; + } else { + saddr->SVE_tag_addr = T_ATM_ABSENT; + saddr->SVE_tag_selector = T_ATM_ABSENT; + saddr->address_format = T_ATM_ABSENT; + } + satm->satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_ABSENT; + satm->satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT; + satm->satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT; + + *addr = (struct sockaddr *)satm; + return (0); +} + + +/* + * Retrieve peer socket address + * + * Called at splnet. + * + * Arguments: + * so pointer to socket + * addr pointer to pointer to contain protocol address + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +int +atm_sock_peeraddr(so, addr) + struct socket *so; + struct sockaddr **addr; +{ + struct sockaddr_atm *satm; + struct t_atm_sap_addr *saddr; + Atm_pcb *atp = sotoatmpcb(so); + Atm_connvc *cvp; + + /* + * Return remote address, if known + */ + satm = KM_ALLOC(sizeof *satm, M_SONAME, M_WAITOK); + if (satm == NULL) + return (ENOMEM); + + KM_ZERO(satm, sizeof(*satm)); + satm->satm_family = AF_ATM; +#if (defined(BSD) && (BSD >= 199103)) + satm->satm_len = sizeof(*satm); +#endif + + saddr = &satm->satm_addr.t_atm_sap_addr; + if (so->so_state & SS_ISCONNECTED) { + cvp = atp->atp_conn->co_connvc; + saddr->SVE_tag_addr = T_ATM_PRESENT; + if (cvp->cvc_flags & CVCF_CALLER) { + ATM_ADDR_COPY(&cvp->cvc_attr.called.addr, saddr); + } else { + if (cvp->cvc_attr.calling.tag == T_ATM_PRESENT) { + ATM_ADDR_COPY(&cvp->cvc_attr.calling.addr, + saddr); + } else { + saddr->SVE_tag_addr = T_ATM_ABSENT; + saddr->address_format = T_ATM_ABSENT; + } + } + if (saddr->address_format == T_ATM_ENDSYS_ADDR) + saddr->SVE_tag_selector = T_ATM_PRESENT; + else + saddr->SVE_tag_selector = T_ATM_ABSENT; + } else { + saddr->SVE_tag_addr = T_ATM_ABSENT; + saddr->SVE_tag_selector = T_ATM_ABSENT; + saddr->address_format = T_ATM_ABSENT; + } + satm->satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_ABSENT; + satm->satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT; + satm->satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT; + + *addr = (struct sockaddr *)satm; + return (0); +} + + +/* + * Common setsockopt processing + * + * Called at splnet. + * + * Arguments: + * so pointer to socket + * sopt pointer to socket option info + * atp pointer to ATM PCB + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +int +atm_sock_setopt(so, sopt, atp) + struct socket *so; + struct sockopt *sopt; + Atm_pcb *atp; +{ + int err = 0; + union { + struct t_atm_aal5 aal5; + struct t_atm_traffic trf; + struct t_atm_bearer brr; + struct t_atm_bhli bhl; + struct t_atm_blli bll; + Atm_addr addr; + struct t_atm_cause cau; + struct t_atm_qos qos; + struct t_atm_transit trn; + struct t_atm_net_intf nif; + struct t_atm_llc llc; + struct t_atm_app_name appn; + } p; + +#define MAXVAL(bits) ((1 << bits) - 1) +#define MAXMASK(bits) (~MAXVAL(bits)) + + switch (sopt->sopt_name) { + + case T_ATM_AAL5: + err = sooptcopyin(sopt, &p.aal5, sizeof p.aal5, sizeof p.aal5); + if (err) + break; + if ((p.aal5.forward_max_SDU_size != T_ATM_ABSENT) && + (p.aal5.forward_max_SDU_size & MAXMASK(16))) + return (EINVAL); + if ((p.aal5.backward_max_SDU_size != T_ATM_ABSENT) && + (p.aal5.backward_max_SDU_size & MAXMASK(16))) + return (EINVAL); + if ((p.aal5.SSCS_type != T_ATM_ABSENT) && + (p.aal5.SSCS_type != T_ATM_NULL) && + (p.aal5.SSCS_type != T_ATM_SSCS_SSCOP_REL) && + (p.aal5.SSCS_type != T_ATM_SSCS_SSCOP_UNREL) && + (p.aal5.SSCS_type != T_ATM_SSCS_FR)) + return (EINVAL); + + if ((p.aal5.forward_max_SDU_size == T_ATM_ABSENT) && + (p.aal5.backward_max_SDU_size == T_ATM_ABSENT) && + (p.aal5.SSCS_type == T_ATM_ABSENT)) + atp->atp_attr.aal.tag = T_ATM_ABSENT; + else { + atp->atp_attr.aal.tag = T_ATM_PRESENT; + atp->atp_attr.aal.type = ATM_AAL5; + atp->atp_attr.aal.v.aal5 = p.aal5; + } + break; + + case T_ATM_TRAFFIC: + err = sooptcopyin(sopt, &p.trf, sizeof p.trf, sizeof p.trf); + if (err) + break; + if ((p.trf.forward.PCR_high_priority != T_ATM_ABSENT) && + (p.trf.forward.PCR_high_priority & MAXMASK(24))) + return (EINVAL); + if (p.trf.forward.PCR_all_traffic & MAXMASK(24)) + return (EINVAL); + if ((p.trf.forward.SCR_high_priority != T_ATM_ABSENT) && + (p.trf.forward.SCR_high_priority & MAXMASK(24))) + return (EINVAL); + if ((p.trf.forward.SCR_all_traffic != T_ATM_ABSENT) && + (p.trf.forward.SCR_all_traffic & MAXMASK(24))) + return (EINVAL); + if ((p.trf.forward.MBS_high_priority != T_ATM_ABSENT) && + (p.trf.forward.MBS_high_priority & MAXMASK(24))) + return (EINVAL); + if ((p.trf.forward.MBS_all_traffic != T_ATM_ABSENT) && + (p.trf.forward.MBS_all_traffic & MAXMASK(24))) + return (EINVAL); + if ((p.trf.forward.tagging != T_YES) && + (p.trf.forward.tagging != T_NO)) + return (EINVAL); + + if ((p.trf.backward.PCR_high_priority != T_ATM_ABSENT) && + (p.trf.backward.PCR_high_priority & MAXMASK(24))) + return (EINVAL); + if (p.trf.backward.PCR_all_traffic & MAXMASK(24)) + return (EINVAL); + if ((p.trf.backward.SCR_high_priority != T_ATM_ABSENT) && + (p.trf.backward.SCR_high_priority & MAXMASK(24))) + return (EINVAL); + if ((p.trf.backward.SCR_all_traffic != T_ATM_ABSENT) && + (p.trf.backward.SCR_all_traffic & MAXMASK(24))) + return (EINVAL); + if ((p.trf.backward.MBS_high_priority != T_ATM_ABSENT) && + (p.trf.backward.MBS_high_priority & MAXMASK(24))) + return (EINVAL); + if ((p.trf.backward.MBS_all_traffic != T_ATM_ABSENT) && + (p.trf.backward.MBS_all_traffic & MAXMASK(24))) + return (EINVAL); + if ((p.trf.backward.tagging != T_YES) && + (p.trf.backward.tagging != T_NO)) + return (EINVAL); + if ((p.trf.best_effort != T_YES) && + (p.trf.best_effort != T_NO)) + return (EINVAL); + + atp->atp_attr.traffic.tag = T_ATM_PRESENT; + atp->atp_attr.traffic.v = p.trf; + break; + + case T_ATM_BEARER_CAP: + err = sooptcopyin(sopt, &p.brr, sizeof p.brr, sizeof p.brr); + if (err) + break; + if ((p.brr.bearer_class != T_ATM_CLASS_A) && + (p.brr.bearer_class != T_ATM_CLASS_C) && + (p.brr.bearer_class != T_ATM_CLASS_X)) + return (EINVAL); + if ((p.brr.traffic_type != T_ATM_NULL) && + (p.brr.traffic_type != T_ATM_CBR) && + (p.brr.traffic_type != T_ATM_VBR)) + return (EINVAL); + if ((p.brr.timing_requirements != T_ATM_NULL) && + (p.brr.timing_requirements != T_ATM_END_TO_END) && + (p.brr.timing_requirements != T_ATM_NO_END_TO_END)) + return (EINVAL); + if ((p.brr.clipping_susceptibility != T_NO) && + (p.brr.clipping_susceptibility != T_YES)) + return (EINVAL); + if ((p.brr.connection_configuration != T_ATM_1_TO_1) && + (p.brr.connection_configuration != T_ATM_1_TO_MANY)) + return (EINVAL); + + atp->atp_attr.bearer.tag = T_ATM_PRESENT; + atp->atp_attr.bearer.v = p.brr; + break; + + case T_ATM_BHLI: + err = sooptcopyin(sopt, &p.bhl, sizeof p.bhl, sizeof p.bhl); + if (err) + break; + if ((p.bhl.ID_type != T_ATM_ABSENT) && + (p.bhl.ID_type != T_ATM_ISO_APP_ID) && + (p.bhl.ID_type != T_ATM_USER_APP_ID) && + (p.bhl.ID_type != T_ATM_VENDOR_APP_ID)) + return (EINVAL); + + if (p.bhl.ID_type == T_ATM_ABSENT) + atp->atp_attr.bhli.tag = T_ATM_ABSENT; + else { + atp->atp_attr.bhli.tag = T_ATM_PRESENT; + atp->atp_attr.bhli.v = p.bhl; + } + break; + + case T_ATM_BLLI: + err = sooptcopyin(sopt, &p.bll, sizeof p.bll, sizeof p.bll); + if (err) + break; + if ((p.bll.layer_2_protocol.ID_type != T_ATM_ABSENT) && + (p.bll.layer_2_protocol.ID_type != T_ATM_SIMPLE_ID) && + (p.bll.layer_2_protocol.ID_type != T_ATM_USER_ID)) + return (EINVAL); + if ((p.bll.layer_2_protocol.mode != T_ATM_ABSENT) && + (p.bll.layer_2_protocol.mode != T_ATM_BLLI_NORMAL_MODE) && + (p.bll.layer_2_protocol.mode != T_ATM_BLLI_EXTENDED_MODE)) + return (EINVAL); + if ((p.bll.layer_2_protocol.window_size != T_ATM_ABSENT) && + (p.bll.layer_2_protocol.window_size < 1)) + return (EINVAL); + + if ((p.bll.layer_3_protocol.ID_type != T_ATM_ABSENT) && + (p.bll.layer_3_protocol.ID_type != T_ATM_SIMPLE_ID) && + (p.bll.layer_3_protocol.ID_type != T_ATM_IPI_ID) && + (p.bll.layer_3_protocol.ID_type != T_ATM_SNAP_ID) && + (p.bll.layer_3_protocol.ID_type != T_ATM_USER_ID)) + return (EINVAL); + if ((p.bll.layer_3_protocol.mode != T_ATM_ABSENT) && + (p.bll.layer_3_protocol.mode != T_ATM_BLLI_NORMAL_MODE) && + (p.bll.layer_3_protocol.mode != T_ATM_BLLI_EXTENDED_MODE)) + return (EINVAL); + if ((p.bll.layer_3_protocol.packet_size != T_ATM_ABSENT) && + (p.bll.layer_3_protocol.packet_size & MAXMASK(4))) + return (EINVAL); + if ((p.bll.layer_3_protocol.window_size != T_ATM_ABSENT) && + (p.bll.layer_3_protocol.window_size < 1)) + return (EINVAL); + + if (p.bll.layer_2_protocol.ID_type == T_ATM_ABSENT) + atp->atp_attr.blli.tag_l2 = T_ATM_ABSENT; + else + atp->atp_attr.blli.tag_l2 = T_ATM_PRESENT; + + if (p.bll.layer_3_protocol.ID_type == T_ATM_ABSENT) + atp->atp_attr.blli.tag_l3 = T_ATM_ABSENT; + else + atp->atp_attr.blli.tag_l3 = T_ATM_PRESENT; + + if ((atp->atp_attr.blli.tag_l2 == T_ATM_PRESENT) || + (atp->atp_attr.blli.tag_l3 == T_ATM_PRESENT)) + atp->atp_attr.blli.v = p.bll; + break; + + case T_ATM_DEST_ADDR: + err = sooptcopyin(sopt, &p.addr, sizeof p.addr, sizeof p.addr); + if (err) + break; + if ((p.addr.address_format != T_ATM_ENDSYS_ADDR) && + (p.addr.address_format != T_ATM_E164_ADDR)) + return (EINVAL); + if (p.addr.address_length > ATM_ADDR_LEN) + return (EINVAL); + + atp->atp_attr.called.tag = T_ATM_PRESENT; + atp->atp_attr.called.addr = p.addr; + break; + + case T_ATM_DEST_SUB: + err = sooptcopyin(sopt, &p.addr, sizeof p.addr, sizeof p.addr); + if (err) + break; + if ((p.addr.address_format != T_ATM_ABSENT) && + (p.addr.address_format != T_ATM_NSAP_ADDR)) + return (EINVAL); + if (p.addr.address_length > ATM_ADDR_LEN) + return (EINVAL); + + /* T_ATM_DEST_ADDR controls tag */ + atp->atp_attr.called.subaddr = p.addr; + break; + + case T_ATM_ORIG_ADDR: + return (EACCES); + + case T_ATM_ORIG_SUB: + return (EACCES); + + case T_ATM_CALLER_ID: + return (EACCES); + + case T_ATM_CAUSE: + err = sooptcopyin(sopt, &p.cau, sizeof p.cau, sizeof p.cau); + if (err) + break; + if ((p.cau.coding_standard != T_ATM_ABSENT) && + (p.cau.coding_standard != T_ATM_ITU_CODING) && + (p.cau.coding_standard != T_ATM_NETWORK_CODING)) + return (EINVAL); + if ((p.cau.location != T_ATM_LOC_USER) && + (p.cau.location != T_ATM_LOC_LOCAL_PRIVATE_NET) && + (p.cau.location != T_ATM_LOC_LOCAL_PUBLIC_NET) && + (p.cau.location != T_ATM_LOC_TRANSIT_NET) && + (p.cau.location != T_ATM_LOC_REMOTE_PUBLIC_NET) && + (p.cau.location != T_ATM_LOC_REMOTE_PRIVATE_NET) && + (p.cau.location != T_ATM_LOC_INTERNATIONAL_NET) && + (p.cau.location != T_ATM_LOC_BEYOND_INTERWORKING)) + return (EINVAL); + + if (p.cau.coding_standard == T_ATM_ABSENT) + atp->atp_attr.cause.tag = T_ATM_ABSENT; + else { + atp->atp_attr.cause.tag = T_ATM_PRESENT; + atp->atp_attr.cause.v = p.cau; + } + break; + + case T_ATM_QOS: + err = sooptcopyin(sopt, &p.qos, sizeof p.qos, sizeof p.qos); + if (err) + break; + if ((p.qos.coding_standard != T_ATM_ABSENT) && + (p.qos.coding_standard != T_ATM_ITU_CODING) && + (p.qos.coding_standard != T_ATM_NETWORK_CODING)) + return (EINVAL); + if ((p.qos.forward.qos_class != T_ATM_QOS_CLASS_0) && + (p.qos.forward.qos_class != T_ATM_QOS_CLASS_1) && + (p.qos.forward.qos_class != T_ATM_QOS_CLASS_2) && + (p.qos.forward.qos_class != T_ATM_QOS_CLASS_3) && + (p.qos.forward.qos_class != T_ATM_QOS_CLASS_4)) + return (EINVAL); + if ((p.qos.backward.qos_class != T_ATM_QOS_CLASS_0) && + (p.qos.backward.qos_class != T_ATM_QOS_CLASS_1) && + (p.qos.backward.qos_class != T_ATM_QOS_CLASS_2) && + (p.qos.backward.qos_class != T_ATM_QOS_CLASS_3) && + (p.qos.backward.qos_class != T_ATM_QOS_CLASS_4)) + return (EINVAL); + + if (p.qos.coding_standard == T_ATM_ABSENT) + atp->atp_attr.qos.tag = T_ATM_ABSENT; + else { + atp->atp_attr.qos.tag = T_ATM_PRESENT; + atp->atp_attr.qos.v = p.qos; + } + break; + + case T_ATM_TRANSIT: + err = sooptcopyin(sopt, &p.trn, sizeof p.trn, sizeof p.trn); + if (err) + break; + if (p.trn.length > T_ATM_MAX_NET_ID) + return (EINVAL); + + if (p.trn.length == 0) + atp->atp_attr.transit.tag = T_ATM_ABSENT; + else { + atp->atp_attr.transit.tag = T_ATM_PRESENT; + atp->atp_attr.transit.v = p.trn; + } + break; + + case T_ATM_ADD_LEAF: + return (EPROTONOSUPPORT); /* XXX */ + + case T_ATM_DROP_LEAF: + return (EPROTONOSUPPORT); /* XXX */ + + case T_ATM_NET_INTF: + err = sooptcopyin(sopt, &p.nif, sizeof p.nif, sizeof p.nif); + if (err) + break; + + atp->atp_attr.nif = atm_nifname(p.nif.net_intf); + if (atp->atp_attr.nif == NULL) + return (ENXIO); + break; + + case T_ATM_LLC: + err = sooptcopyin(sopt, &p.llc, sizeof p.llc, sizeof p.llc); + if (err) + break; + if ((p.llc.llc_len < T_ATM_LLC_MIN_LEN) || + (p.llc.llc_len > T_ATM_LLC_MAX_LEN)) + return (EINVAL); + + atp->atp_attr.llc.tag = T_ATM_PRESENT; + atp->atp_attr.llc.v = p.llc; + break; + + case T_ATM_APP_NAME: + err = sooptcopyin(sopt, &p.appn, sizeof p.appn, sizeof p.appn); + if (err) + break; + + strncpy(atp->atp_name, p.appn.app_name, T_ATM_APP_NAME_LEN); + break; + + default: + return (ENOPROTOOPT); + } + + return (err); +} + + +/* + * Common getsockopt processing + * + * Called at splnet. + * + * Arguments: + * so pointer to socket + * sopt pointer to socket option info + * atp pointer to ATM PCB + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +int +atm_sock_getopt(so, sopt, atp) + struct socket *so; + struct sockopt *sopt; + Atm_pcb *atp; +{ + Atm_attributes *ap; + + /* + * If socket is connected, return attributes for the VCC in use, + * otherwise just return what the user has setup so far. + */ + if (so->so_state & SS_ISCONNECTED) + ap = &atp->atp_conn->co_connvc->cvc_attr; + else + ap = &atp->atp_attr; + + switch (sopt->sopt_name) { + + case T_ATM_AAL5: + if ((ap->aal.tag == T_ATM_PRESENT) && + (ap->aal.type == ATM_AAL5)) { + return (sooptcopyout(sopt, &ap->aal.v.aal5, + sizeof ap->aal.v.aal5)); + } else { + return (ENOENT); + } + break; + + case T_ATM_TRAFFIC: + if (ap->traffic.tag == T_ATM_PRESENT) { + return (sooptcopyout(sopt, &ap->traffic.v, + sizeof ap->traffic.v)); + } else { + return (ENOENT); + } + break; + + case T_ATM_BEARER_CAP: + if (ap->bearer.tag == T_ATM_PRESENT) { + return (sooptcopyout(sopt, &ap->bearer.v, + sizeof ap->bearer.v)); + } else { + return (ENOENT); + } + break; + + case T_ATM_BHLI: + if (ap->bhli.tag == T_ATM_PRESENT) { + return (sooptcopyout(sopt, &ap->bhli.v, + sizeof ap->bhli.v)); + } else { + return (ENOENT); + } + break; + + case T_ATM_BLLI: + if ((ap->blli.tag_l2 == T_ATM_PRESENT) || + (ap->blli.tag_l3 == T_ATM_PRESENT)) { + return (sooptcopyout(sopt, &ap->blli.v, + sizeof ap->blli.v)); + } else { + return (ENOENT); + } + break; + + case T_ATM_DEST_ADDR: + if (ap->called.tag == T_ATM_PRESENT) { + return (sooptcopyout(sopt, &ap->called.addr, + sizeof ap->called.addr)); + } else { + return (ENOENT); + } + break; + + case T_ATM_DEST_SUB: + if (ap->called.tag == T_ATM_PRESENT) { + return (sooptcopyout(sopt, &ap->called.subaddr, + sizeof ap->called.subaddr)); + } else { + return (ENOENT); + } + break; + + case T_ATM_ORIG_ADDR: + if (ap->calling.tag == T_ATM_PRESENT) { + return (sooptcopyout(sopt, &ap->calling.addr, + sizeof ap->calling.addr)); + } else { + return (ENOENT); + } + break; + + case T_ATM_ORIG_SUB: + if (ap->calling.tag == T_ATM_PRESENT) { + return (sooptcopyout(sopt, &ap->calling.subaddr, + sizeof ap->calling.subaddr)); + } else { + return (ENOENT); + } + break; + + case T_ATM_CALLER_ID: + if (ap->calling.tag == T_ATM_PRESENT) { + return (sooptcopyout(sopt, &ap->calling.cid, + sizeof ap->calling.cid)); + } else { + return (ENOENT); + } + break; + + case T_ATM_CAUSE: + if (ap->cause.tag == T_ATM_PRESENT) { + return (sooptcopyout(sopt, &ap->cause.v, + sizeof ap->cause.v)); + } else { + return (ENOENT); + } + break; + + case T_ATM_QOS: + if (ap->qos.tag == T_ATM_PRESENT) { + return (sooptcopyout(sopt, &ap->qos.v, + sizeof ap->qos.v)); + } else { + return (ENOENT); + } + break; + + case T_ATM_TRANSIT: + if (ap->transit.tag == T_ATM_PRESENT) { + return (sooptcopyout(sopt, &ap->transit.v, + sizeof ap->transit.v)); + } else { + return (ENOENT); + } + break; + + case T_ATM_LEAF_IND: + return (EPROTONOSUPPORT); /* XXX */ + + case T_ATM_NET_INTF: + if (ap->nif) { + struct t_atm_net_intf netif; + struct ifnet *ifp; + + ifp = &ap->nif->nif_if; + (void) sprintf(netif.net_intf, "%s%d", + ifp->if_name, ifp->if_unit); + return (sooptcopyout(sopt, &netif, + sizeof netif)); + } else { + return (ENOENT); + } + break; + + case T_ATM_LLC: + if (ap->llc.tag == T_ATM_PRESENT) { + return (sooptcopyout(sopt, &ap->llc.v, + sizeof ap->llc.v)); + } else { + return (ENOENT); + } + break; + + default: + return (ENOPROTOOPT); + } + + return (0); +} + + +/* + * Process Socket VCC Connected Notification + * + * Arguments: + * toku owner's connection token (atm_pcb protocol block) + * + * Returns: + * none + * + */ +void +atm_sock_connected(toku) + void *toku; +{ + Atm_pcb *atp = (Atm_pcb *)toku; + + /* + * Connection is setup + */ + atm_sock_stat.as_conncomp[atp->atp_type]++; + soisconnected(atp->atp_socket); +} + + +/* + * Process Socket VCC Cleared Notification + * + * Arguments: + * toku owner's connection token (atm_pcb protocol block) + * cause pointer to cause code + * + * Returns: + * none + * + */ +void +atm_sock_cleared(toku, cause) + void *toku; + struct t_atm_cause *cause; +{ + Atm_pcb *atp = (Atm_pcb *)toku; + struct socket *so; + + so = atp->atp_socket; + + /* + * Save call clearing cause + */ + atp->atp_attr.cause.tag = T_ATM_PRESENT; + atp->atp_attr.cause.v = *cause; + + /* + * Set user error code + */ + if (so->so_state & SS_ISCONNECTED) { + so->so_error = ECONNRESET; + atm_sock_stat.as_connclr[atp->atp_type]++; + } else { + so->so_error = ECONNREFUSED; + atm_sock_stat.as_connfail[atp->atp_type]++; + } + + /* + * Connection is gone + */ + atp->atp_conn = NULL; + soisdisconnected(so); + + /* + * Cleanup failed incoming connection setup + */ + if (so->so_state & SS_NOFDREF) { + (void) atm_sock_detach(so); + } +} + diff --git a/sys/netatm/atm_stack.h b/sys/netatm/atm_stack.h new file mode 100644 index 0000000..abd32c4 --- /dev/null +++ b/sys/netatm/atm_stack.h @@ -0,0 +1,287 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_stack.h,v 1.5 1998/02/19 19:59:59 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * ATM Stack definitions + * + */ + +#ifndef _NETATM_ATM_STACK_H +#define _NETATM_ATM_STACK_H + +#ifdef ATM_KERNEL +/* + * Structure used to define a kernel-provided ATM stack service and its + * associated entry points. Each stack service provider must register + * themselves before they will be used. ATM stack service providers include + * kernel modules (both linked and loaded) and device drivers, which must list + * (via its atm_pif) any of its available hardware-supplied stack services + * (such as on-card AAL processing). + */ +struct stack_defn { + struct stack_defn *sd_next; /* Next in registry list */ + Sap_t sd_sap; /* Stack instance SAP */ + u_char sd_flag; /* Flags (see below) */ +/* Exported functions */ + int (*sd_inst) /* Stack instantiation */ + __P((struct stack_defn **, Atm_connvc *)); + void (*sd_lower) /* Lower (from above) command handler */ + __P((int, void *, int, int)); + void (*sd_upper) /* Upper (from below) command handler */ + __P((int, void *, int, int)); +/* Variables used during stack instantiation */ + void *sd_toku; /* Stack service instance token */ +}; + +/* + * Stack Service Flags + */ +#define SDF_TERM 0x01 /* Terminal (to lowest layer) service */ + + +/* + * Stack Specification List + * + * The list names the stack services and their layering relationships in + * order to construct a stack to provide the protocol services defined + * by the list. The list is ordered starting from the stack service + * interfacing with the user "down" to the ATM cell service. + */ +#define STACK_CNT 8 /* Max services in a stack list */ +struct stack_list { + Sap_t sl_sap[STACK_CNT]; /* Stack service SAP list */ +}; + + +/* + * Structure used during the construction and instantiation of a stack + * instance from a supplied stack list. It contains pointers to the stack + * service definitions which will be used to implement the stack. The first + * element in the array is reserved for the user's "stack service". + */ +struct stack_inst { + struct stack_defn *si_srvc[STACK_CNT+1]; /* Assigned services */ +}; + + +/* + * Macros to update buffer headroom values during stack instantiation. + * + * These values are advisory, i.e. every service must verify the amount + * of available space in input/output messages and allocate new buffers + * if needed. + * + * The 'maximum' and 'minimum' values used below may be chosen by a + * service to reflect the typical, expected message traffic pattern + * for a specific connection. + * + * The macro arguments are: + * cvp = pointer to connection vcc; + * hi = maximum amount of buffer headroom required by the current + * service during input message processing; + * si = minimum amount of buffer data stripped off the front + * of an input message by the current service; + * ho = maximum amount of buffer headroom required by the current + * service during output message processing; + * ao = maximum amount of buffer data added to the front + * of an output message by the current service; + */ +#define HEADIN(cvp, hi, si) \ +{ \ + short t = (cvp)->cvc_attr.headin - (si); \ + t = (t >= (hi)) ? t : (hi); \ + (cvp)->cvc_attr.headin = roundup(t, sizeof(long)); \ +} + +#define HEADOUT(cvp, ho, ao) \ +{ \ + short t = (cvp)->cvc_attr.headout + (ao); \ + t = (t >= (ho)) ? t : (ho); \ + (cvp)->cvc_attr.headout = roundup(t, sizeof(long)); \ +} + + +/* + * Stack command codes - All stack command codes are specific to the + * defined stack SAP across which the command is used. Command values 0-15 + * are reserved for any common codes, which all stack SAPs must support. + */ +#define STKCMD(s, d, v) (((s) << 16) | (d) | (v)) +#define STKCMD_DOWN 0 +#define STKCMD_UP 0x00008000 +#define STKCMD_SAP_MASK 0xffff0000 +#define STKCMD_VAL_MASK 0x00007fff + +/* Common command values (0-15) */ +#define CCV_INIT 1 /* DOWN */ +#define CCV_TERM 2 /* DOWN */ + +/* SAP_ATM */ +#define ATM_INIT STKCMD(SAP_ATM, STKCMD_DOWN, CCV_INIT) +#define ATM_TERM STKCMD(SAP_ATM, STKCMD_DOWN, CCV_TERM) +#define ATM_DATA_REQ STKCMD(SAP_ATM, STKCMD_DOWN, 16) +#define ATM_DATA_IND STKCMD(SAP_ATM, STKCMD_UP, 17) + +/* SAP_SAR */ +#define SAR_INIT STKCMD(SAP_SAR, STKCMD_DOWN, CCV_INIT) +#define SAR_TERM STKCMD(SAP_SAR, STKCMD_DOWN, CCV_TERM) +#define SAR_UNITDATA_INV STKCMD(SAP_SAR, STKCMD_DOWN, 16) +#define SAR_UNITDATA_SIG STKCMD(SAP_SAR, STKCMD_UP, 17) +#define SAR_UABORT_INV STKCMD(SAP_SAR, STKCMD_DOWN, 18) +#define SAR_UABORT_SIG STKCMD(SAP_SAR, STKCMD_UP, 19) +#define SAR_PABORT_SIG STKCMD(SAP_SAR, STKCMD_UP, 20) + +/* SAP_CPCS */ +#define CPCS_INIT STKCMD(SAP_CPCS, STKCMD_DOWN, CCV_INIT) +#define CPCS_TERM STKCMD(SAP_CPCS, STKCMD_DOWN, CCV_TERM) +#define CPCS_UNITDATA_INV STKCMD(SAP_CPCS, STKCMD_DOWN, 16) +#define CPCS_UNITDATA_SIG STKCMD(SAP_CPCS, STKCMD_UP, 17) +#define CPCS_UABORT_INV STKCMD(SAP_CPCS, STKCMD_DOWN, 18) +#define CPCS_UABORT_SIG STKCMD(SAP_CPCS, STKCMD_UP, 19) +#define CPCS_PABORT_SIG STKCMD(SAP_CPCS, STKCMD_UP, 20) + +/* SAP_SSCOP */ +#define SSCOP_INIT STKCMD(SAP_SSCOP, STKCMD_DOWN, CCV_INIT) +#define SSCOP_TERM STKCMD(SAP_SSCOP, STKCMD_DOWN, CCV_TERM) +#define SSCOP_ESTABLISH_REQ STKCMD(SAP_SSCOP, STKCMD_DOWN, 16) +#define SSCOP_ESTABLISH_IND STKCMD(SAP_SSCOP, STKCMD_UP, 17) +#define SSCOP_ESTABLISH_RSP STKCMD(SAP_SSCOP, STKCMD_DOWN, 18) +#define SSCOP_ESTABLISH_CNF STKCMD(SAP_SSCOP, STKCMD_UP, 19) +#define SSCOP_RELEASE_REQ STKCMD(SAP_SSCOP, STKCMD_DOWN, 20) +#define SSCOP_RELEASE_IND STKCMD(SAP_SSCOP, STKCMD_UP, 21) +#define SSCOP_RELEASE_CNF STKCMD(SAP_SSCOP, STKCMD_UP, 22) +#define SSCOP_DATA_REQ STKCMD(SAP_SSCOP, STKCMD_DOWN, 23) +#define SSCOP_DATA_IND STKCMD(SAP_SSCOP, STKCMD_UP, 24) +#define SSCOP_RESYNC_REQ STKCMD(SAP_SSCOP, STKCMD_DOWN, 25) +#define SSCOP_RESYNC_IND STKCMD(SAP_SSCOP, STKCMD_UP, 26) +#define SSCOP_RESYNC_RSP STKCMD(SAP_SSCOP, STKCMD_DOWN, 27) +#define SSCOP_RESYNC_CNF STKCMD(SAP_SSCOP, STKCMD_UP, 28) +#define SSCOP_RECOVER_IND STKCMD(SAP_SSCOP, STKCMD_UP, 29) +#define SSCOP_RECOVER_RSP STKCMD(SAP_SSCOP, STKCMD_DOWN, 30) +#define SSCOP_UNITDATA_REQ STKCMD(SAP_SSCOP, STKCMD_DOWN, 31) +#define SSCOP_UNITDATA_IND STKCMD(SAP_SSCOP, STKCMD_UP, 32) +#define SSCOP_RETRIEVE_REQ STKCMD(SAP_SSCOP, STKCMD_DOWN, 33) +#define SSCOP_RETRIEVE_IND STKCMD(SAP_SSCOP, STKCMD_UP, 34) +#define SSCOP_RETRIEVECMP_IND STKCMD(SAP_SSCOP, STKCMD_UP, 35) + +/* SAP_SSCF_UNI */ +#define SSCF_UNI_INIT STKCMD(SAP_SSCF_UNI, STKCMD_DOWN, CCV_INIT) +#define SSCF_UNI_TERM STKCMD(SAP_SSCF_UNI, STKCMD_DOWN, CCV_TERM) +#define SSCF_UNI_ESTABLISH_REQ STKCMD(SAP_SSCF_UNI, STKCMD_DOWN, 16) +#define SSCF_UNI_ESTABLISH_IND STKCMD(SAP_SSCF_UNI, STKCMD_UP, 17) +#define SSCF_UNI_ESTABLISH_CNF STKCMD(SAP_SSCF_UNI, STKCMD_UP, 18) +#define SSCF_UNI_RELEASE_REQ STKCMD(SAP_SSCF_UNI, STKCMD_DOWN, 19) +#define SSCF_UNI_RELEASE_IND STKCMD(SAP_SSCF_UNI, STKCMD_UP, 20) +#define SSCF_UNI_RELEASE_CNF STKCMD(SAP_SSCF_UNI, STKCMD_UP, 21) +#define SSCF_UNI_DATA_REQ STKCMD(SAP_SSCF_UNI, STKCMD_DOWN, 22) +#define SSCF_UNI_DATA_IND STKCMD(SAP_SSCF_UNI, STKCMD_UP, 23) +#define SSCF_UNI_UNITDATA_REQ STKCMD(SAP_SSCF_UNI, STKCMD_DOWN, 24) +#define SSCF_UNI_UNITDATA_IND STKCMD(SAP_SSCF_UNI, STKCMD_UP, 25) + + +/* + * The STACK_CALL macro must be used for all stack calls between adjacent + * entities. In order to avoid the problem with recursive stack calls + * modifying protocol state, this macro will only allow calls to proceed if + * they are not "against the flow" of any currently pending calls for a + * stack instance. If the requested call can't be processed now, it will + * be deferred and queued until a later, safe time (but before control is + * returned back to the kernel scheduler) when it will be dispatched. + * + * The STACK_CALL macro arguments are: + * cmd = command code; + * fn = Destination entity processing function + * tok = Destination layer's session token; + * cvp = Connection VCC address; + * a1 = command specific argument; + * a2 = command specific argument; + * ret = call result value (0 => success) + * + * The receiving entity command processing function prototype is: + * + * void (fn)(int cmd, int tok, int arg1, int arg2) + * + */ +#define STACK_CALL(cmd, fn, tok, cvp, a1, a2, ret) \ +{ \ + if ((cmd) & STKCMD_UP) { \ + if ((cvp)->cvc_downcnt) { \ + (ret) = atm_stack_enq((cmd), (fn), (tok), \ + (cvp), (a1), (a2)); \ + } else { \ + (cvp)->cvc_upcnt++; \ + (*fn)(cmd, tok, a1, a2); \ + (cvp)->cvc_upcnt--; \ + (ret) = 0; \ + } \ + } else { \ + if ((cvp)->cvc_upcnt) { \ + (ret) = atm_stack_enq((cmd), (fn), (tok), \ + (cvp), (a1), (a2)); \ + } else { \ + (cvp)->cvc_downcnt++; \ + (*fn)(cmd, tok, a1, a2); \ + (cvp)->cvc_downcnt--; \ + (ret) = 0; \ + } \ + } \ +} + + +/* + * Stack queue entry - The stack queue will contain stack calls which have + * been deferred in order to avoid recursive calls to a single protocol + * control block. The queue entries are allocated from its own storage pool. + */ +struct stackq_entry { + struct stackq_entry *sq_next; /* Next entry in queue */ + int sq_cmd; /* Stack command */ + void (*sq_func) /* Destination function */ + __P((int, void *, int, int)); + void *sq_token; /* Destination token */ + int sq_arg1; /* Command-specific argument */ + int sq_arg2; /* Command-specific argument */ + Atm_connvc *sq_connvc; /* Connection VCC */ +}; + + +/* + * Macro to avoid unnecessary function call when draining the stack queue. + */ +#define STACK_DRAIN() \ +{ \ + if (atm_stackq_head) \ + atm_stack_drain(); \ +} +#endif /* ATM_KERNEL */ + +#endif /* _NETATM_ATM_STACK_H */ diff --git a/sys/netatm/atm_subr.c b/sys/netatm/atm_subr.c new file mode 100644 index 0000000..40fc433 --- /dev/null +++ b/sys/netatm/atm_subr.c @@ -0,0 +1,970 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_subr.c,v 1.10 1998/05/18 19:06:02 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * Miscellaneous ATM subroutines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_subr.c,v 1.10 1998/05/18 19:06:02 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + + +/* + * Global variables + */ +struct atm_pif *atm_interface_head = NULL; +struct atm_ncm *atm_netconv_head = NULL; +Atm_endpoint *atm_endpoints[ENDPT_MAX+1] = {NULL}; +struct sp_info *atm_pool_head = NULL; +struct stackq_entry *atm_stackq_head = NULL, *atm_stackq_tail; +struct ifqueue atm_intrq; +#ifdef sgi +int atm_intr_index; +#endif +struct atm_sock_stat atm_sock_stat = {0}; +int atm_init = 0; +int atm_debug = 0; +int atm_dev_print = 0; +int atm_print_data = 0; +int atm_version = ATM_VERSION; +struct timeval atm_debugtime = {0, 0}; + +struct sp_info atm_attributes_pool = { + "atm attributes pool", /* si_name */ + sizeof(Atm_attributes), /* si_blksiz */ + 10, /* si_blkcnt */ + 100 /* si_maxallow */ +}; + + +/* + * Local functions + */ +static void atm_compact __P((struct atm_time *)); +static KTimeout_ret atm_timexp __P((void *)); + +/* + * Local variables + */ +static struct atm_time *atm_timeq = NULL; +static struct atm_time atm_compactimer = {0, 0}; + +static struct sp_info atm_stackq_pool = { + "Service stack queue pool", /* si_name */ + sizeof(struct stackq_entry), /* si_blksiz */ + 10, /* si_blkcnt */ + 10 /* si_maxallow */ +}; + + +/* + * Initialize ATM kernel + * + * Performs any initialization required before things really get underway. + * Called from ATM domain initialization or from first registration function + * which gets called. + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +atm_initialize() +{ + /* + * Never called from interrupts, so no locking needed + */ + if (atm_init) + return; + atm_init = 1; + +#ifndef __FreeBSD__ + /* + * Add ATM protocol family + */ + (void) protocol_family(&atmdomain, NULL, NULL); +#endif + + atm_intrq.ifq_maxlen = ATM_INTRQ_MAX; +#ifdef sgi + atm_intr_index = register_isr(atm_intr); +#endif + + /* + * Initialize subsystems + */ + atm_aal5_init(); + + /* + * Prime the timer + */ + (void) timeout(atm_timexp, (void *)0, hz/ATM_HZ); + + /* + * Start the compaction timer + */ + atm_timeout(&atm_compactimer, SPOOL_COMPACT, atm_compact); +} + + +/* + * Allocate a Control Block + * + * Gets a new control block allocated from the specified storage pool, + * acquiring memory for new pool chunks if required. The returned control + * block's contents will be cleared. + * + * Arguments: + * sip pointer to sp_info for storage pool + * + * Returns: + * addr pointer to allocated control block + * 0 allocation failed + * + */ +void * +atm_allocate(sip) + struct sp_info *sip; +{ + void *bp; + struct sp_chunk *scp; + struct sp_link *slp; + int s = splnet(); + + /* + * Count calls + */ + sip->si_allocs++; + + /* + * Are there any free in the pool? + */ + if (sip->si_free) { + + /* + * Find first chunk with a free block + */ + for (scp = sip->si_poolh; scp; scp = scp->sc_next) { + if (scp->sc_freeh != NULL) + break; + } + + } else { + + /* + * No free blocks - have to allocate a new + * chunk (but put a limit to this) + */ + struct sp_link *slp_next; + int i; + + /* + * First time for this pool?? + */ + if (sip->si_chunksiz == 0) { + size_t n; + + /* + * Initialize pool information + */ + n = sizeof(struct sp_chunk) + + sip->si_blkcnt * + (sip->si_blksiz + sizeof(struct sp_link)); + sip->si_chunksiz = roundup(n, SPOOL_ROUNDUP); + + /* + * Place pool on kernel chain + */ + LINK2TAIL(sip, struct sp_info, atm_pool_head, si_next); + } + + if (sip->si_chunks >= sip->si_maxallow) { + sip->si_fails++; + (void) splx(s); + return (NULL); + } + + scp = (struct sp_chunk *) + KM_ALLOC(sip->si_chunksiz, M_DEVBUF, M_NOWAIT); + if (scp == NULL) { + sip->si_fails++; + (void) splx(s); + return (NULL); + } + scp->sc_next = NULL; + scp->sc_info = sip; + scp->sc_magic = SPOOL_MAGIC; + scp->sc_used = 0; + + /* + * Divy up chunk into free blocks + */ + slp = (struct sp_link *)(scp + 1); + scp->sc_freeh = slp; + + for (i = sip->si_blkcnt; i > 1; i--) { + slp_next = (struct sp_link *)((caddr_t)(slp + 1) + + sip->si_blksiz); + slp->sl_u.slu_next = slp_next; + slp = slp_next; + } + slp->sl_u.slu_next = NULL; + scp->sc_freet = slp; + + /* + * Add new chunk to end of pool + */ + if (sip->si_poolh) + sip->si_poolt->sc_next = scp; + else + sip->si_poolh = scp; + sip->si_poolt = scp; + + sip->si_chunks++; + sip->si_total += sip->si_blkcnt; + sip->si_free += sip->si_blkcnt; + if (sip->si_chunks > sip->si_maxused) + sip->si_maxused = sip->si_chunks; + } + + /* + * Allocate the first free block in chunk + */ + slp = scp->sc_freeh; + scp->sc_freeh = slp->sl_u.slu_next; + scp->sc_used++; + sip->si_free--; + bp = (slp + 1); + + /* + * Save link back to pool chunk + */ + slp->sl_u.slu_chunk = scp; + + /* + * Clear out block + */ + KM_ZERO(bp, sip->si_blksiz); + + (void) splx(s); + return (bp); +} + + +/* + * Free a Control Block + * + * Returns a previously allocated control block back to the owners + * storage pool. + * + * Arguments: + * bp pointer to block to be freed + * + * Returns: + * none + * + */ +void +atm_free(bp) + void *bp; +{ + struct sp_info *sip; + struct sp_chunk *scp; + struct sp_link *slp; + int s = splnet(); + + /* + * Get containing chunk and pool info + */ + slp = (struct sp_link *)bp; + slp--; + scp = slp->sl_u.slu_chunk; + if (scp->sc_magic != SPOOL_MAGIC) + panic("atm_free: chunk magic missing"); + sip = scp->sc_info; + + /* + * Add block to free chain + */ + if (scp->sc_freeh) { + scp->sc_freet->sl_u.slu_next = slp; + scp->sc_freet = slp; + } else + scp->sc_freeh = scp->sc_freet = slp; + slp->sl_u.slu_next = NULL; + sip->si_free++; + scp->sc_used--; + + (void) splx(s); + return; +} + + +/* + * Storage Pool Compaction + * + * Called periodically in order to perform compaction of the + * storage pools. Each pool will be checked to see if any chunks + * can be freed, taking some care to avoid freeing too many chunks + * in order to avoid memory thrashing. + * + * Called at splnet. + * + * Arguments: + * tip pointer to timer control block (atm_compactimer) + * + * Returns: + * none + * + */ +static void +atm_compact(tip) + struct atm_time *tip; +{ + struct sp_info *sip; + struct sp_chunk *scp; + int i; + struct sp_chunk *scp_prev; + + /* + * Check out all storage pools + */ + for (sip = atm_pool_head; sip; sip = sip->si_next) { + + /* + * Always keep a minimum number of chunks around + */ + if (sip->si_chunks <= SPOOL_MIN_CHUNK) + continue; + + /* + * Maximum chunks to free at one time will leave + * pool with at least 50% utilization, but never + * go below minimum chunk count. + */ + i = ((sip->si_free * 2) - sip->si_total) / sip->si_blkcnt; + i = MIN(i, sip->si_chunks - SPOOL_MIN_CHUNK); + + /* + * Look for chunks to free + */ + scp_prev = NULL; + for (scp = sip->si_poolh; scp && i > 0; ) { + + if (scp->sc_used == 0) { + + /* + * Found a chunk to free, so do it + */ + if (scp_prev) { + scp_prev->sc_next = scp->sc_next; + if (sip->si_poolt == scp) + sip->si_poolt = scp_prev; + } else + sip->si_poolh = scp->sc_next; + + KM_FREE((caddr_t)scp, sip->si_chunksiz, + M_DEVBUF); + + /* + * Update pool controls + */ + sip->si_chunks--; + sip->si_total -= sip->si_blkcnt; + sip->si_free -= sip->si_blkcnt; + i--; + if (scp_prev) + scp = scp_prev->sc_next; + else + scp = sip->si_poolh; + } else { + scp_prev = scp; + scp = scp->sc_next; + } + } + } + + /* + * Restart the compaction timer + */ + atm_timeout(&atm_compactimer, SPOOL_COMPACT, atm_compact); + + return; +} + + +/* + * Release a Storage Pool + * + * Frees all dynamic storage acquired for a storage pool. + * This function is normally called just prior to a module's unloading. + * + * Arguments: + * sip pointer to sp_info for storage pool + * + * Returns: + * none + * + */ +void +atm_release_pool(sip) + struct sp_info *sip; +{ + struct sp_chunk *scp, *scp_next; + int s = splnet(); + + /* + * Free each chunk in pool + */ + for (scp = sip->si_poolh; scp; scp = scp_next) { + + /* + * Check for memory leaks + */ + if (scp->sc_used) + panic("atm_release_pool: unfreed blocks"); + + scp_next = scp->sc_next; + + KM_FREE((caddr_t)scp, sip->si_chunksiz, M_DEVBUF); + } + + /* + * Update pool controls + */ + sip->si_poolh = NULL; + sip->si_chunks = 0; + sip->si_total = 0; + sip->si_free = 0; + + /* + * Unlink pool from active chain + */ + sip->si_chunksiz = 0; + UNLINK(sip, struct sp_info, atm_pool_head, si_next); + + (void) splx(s); + return; +} + + +/* + * Handle timer tick expiration + * + * Decrement tick count in first block on timer queue. If there + * are blocks with expired timers, call their timeout function. + * This function is called ATM_HZ times per second. + * + * Arguments: + * arg argument passed on timeout() call + * + * Returns: + * none + * + */ +static KTimeout_ret +atm_timexp(arg) + void *arg; +{ + struct atm_time *tip; + int s = splimp(); + + + /* + * Decrement tick count + */ + if (((tip = atm_timeq) == NULL) || (--tip->ti_ticks > 0)) { + goto restart; + } + + /* + * Stack queue should have been drained + */ +#ifdef DIAGNOSTIC + if (atm_stackq_head != NULL) + panic("atm_timexp: stack queue not empty"); +#endif + + /* + * Dispatch expired timers + */ + while (((tip = atm_timeq) != NULL) && (tip->ti_ticks == 0)) { + void (*func)__P((struct atm_time *)); + + /* + * Remove expired block from queue + */ + atm_timeq = tip->ti_next; + tip->ti_flag &= ~TIF_QUEUED; + + /* + * Call timeout handler (with network interrupts locked out) + */ + func = tip->ti_func; + (void) splx(s); + s = splnet(); + (*func)(tip); + (void) splx(s); + s = splimp(); + + /* + * Drain any deferred calls + */ + STACK_DRAIN(); + } + +restart: + /* + * Restart the timer + */ + (void) splx(s); + (void) timeout(atm_timexp, (void *)0, hz/ATM_HZ); + + return; +} + + +/* + * Schedule a control block timeout + * + * Place the supplied timer control block on the timer queue. The + * function (func) will be called in 't' timer ticks with the + * control block address as its only argument. There are ATM_HZ + * timer ticks per second. The ticks value stored in each block is + * a delta of the number of ticks from the previous block in the queue. + * Thus, for each tick interval, only the first block in the queue + * needs to have its tick value decremented. + * + * Arguments: + * tip pointer to timer control block + * t number of timer ticks until expiration + * func pointer to function to call at expiration + * + * Returns: + * none + * + */ +void +atm_timeout(tip, t, func) + struct atm_time *tip; + int t; + void (*func)__P((struct atm_time *)); +{ + struct atm_time *tip1, *tip2; + int s; + + + /* + * Check for double queueing error + */ + if (tip->ti_flag & TIF_QUEUED) + panic("atm_timeout: double queueing"); + + /* + * Make sure we delay at least a little bit + */ + if (t <= 0) + t = 1; + + /* + * Find out where we belong on the queue + */ + s = splimp(); + for (tip1 = NULL, tip2 = atm_timeq; tip2 && (tip2->ti_ticks <= t); + tip1 = tip2, tip2 = tip1->ti_next) { + t -= tip2->ti_ticks; + } + + /* + * Place ourselves on queue and update timer deltas + */ + if (tip1 == NULL) + atm_timeq = tip; + else + tip1->ti_next = tip; + tip->ti_next = tip2; + + if (tip2) + tip2->ti_ticks -= t; + + /* + * Setup timer block + */ + tip->ti_flag |= TIF_QUEUED; + tip->ti_ticks = t; + tip->ti_func = func; + + (void) splx(s); + return; +} + + +/* + * Cancel a timeout + * + * Remove the supplied timer control block from the timer queue. + * + * Arguments: + * tip pointer to timer control block + * + * Returns: + * 0 control block successfully dequeued + * 1 control block not on timer queue + * + */ +int +atm_untimeout(tip) + struct atm_time *tip; +{ + struct atm_time *tip1, *tip2; + int s; + + /* + * Is control block queued? + */ + if ((tip->ti_flag & TIF_QUEUED) == 0) + return(1); + + /* + * Find control block on the queue + */ + s = splimp(); + for (tip1 = NULL, tip2 = atm_timeq; tip2 && (tip2 != tip); + tip1 = tip2, tip2 = tip1->ti_next) { + } + + if (tip2 == NULL) { + (void) splx(s); + return (1); + } + + /* + * Remove block from queue and update timer deltas + */ + tip2 = tip->ti_next; + if (tip1 == NULL) + atm_timeq = tip2; + else + tip1->ti_next = tip2; + + if (tip2) + tip2->ti_ticks += tip->ti_ticks; + + /* + * Reset timer block + */ + tip->ti_flag &= ~TIF_QUEUED; + + (void) splx(s); + return (0); +} + + +/* + * Queue a Stack Call + * + * Queues a stack call which must be deferred to the global stack queue. + * The call parameters are stored in entries which are allocated from the + * stack queue storage pool. + * + * Arguments: + * cmd stack command + * func destination function + * token destination layer's token + * cvp pointer to connection vcc + * arg1 command argument + * arg2 command argument + * + * Returns: + * 0 call queued + * errno call not queued - reason indicated + * + */ +int +atm_stack_enq(cmd, func, token, cvp, arg1, arg2) + int cmd; + void (*func)__P((int, void *, int, int)); + void *token; + Atm_connvc *cvp; + int arg1; + int arg2; +{ + struct stackq_entry *sqp; + int s = splnet(); + + /* + * Get a new queue entry for this call + */ + sqp = (struct stackq_entry *)atm_allocate(&atm_stackq_pool); + if (sqp == NULL) { + (void) splx(s); + return (ENOMEM); + } + + /* + * Fill in new entry + */ + sqp->sq_next = NULL; + sqp->sq_cmd = cmd; + sqp->sq_func = func; + sqp->sq_token = token; + sqp->sq_arg1 = arg1; + sqp->sq_arg2 = arg2; + sqp->sq_connvc = cvp; + + /* + * Put new entry at end of queue + */ + if (atm_stackq_head == NULL) + atm_stackq_head = sqp; + else + atm_stackq_tail->sq_next = sqp; + atm_stackq_tail = sqp; + + (void) splx(s); + return (0); +} + + +/* + * Drain the Stack Queue + * + * Dequeues and processes entries from the global stack queue. + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +atm_stack_drain() +{ + struct stackq_entry *sqp, *qprev, *qnext; + int s = splnet(); + int cnt; + + /* + * Loop thru entire queue until queue is empty + * (but panic rather loop forever) + */ + do { + cnt = 0; + qprev = NULL; + for (sqp = atm_stackq_head; sqp; ) { + + /* + * Got an eligible entry, do STACK_CALL stuff + */ + if (sqp->sq_cmd & STKCMD_UP) { + if (sqp->sq_connvc->cvc_downcnt) { + + /* + * Cant process now, skip it + */ + qprev = sqp; + sqp = sqp->sq_next; + continue; + } + + /* + * OK, dispatch the call + */ + sqp->sq_connvc->cvc_upcnt++; + (*sqp->sq_func)(sqp->sq_cmd, + sqp->sq_token, + sqp->sq_arg1, + sqp->sq_arg2); + sqp->sq_connvc->cvc_upcnt--; + } else { + if (sqp->sq_connvc->cvc_upcnt) { + + /* + * Cant process now, skip it + */ + qprev = sqp; + sqp = sqp->sq_next; + continue; + } + + /* + * OK, dispatch the call + */ + sqp->sq_connvc->cvc_downcnt++; + (*sqp->sq_func)(sqp->sq_cmd, + sqp->sq_token, + sqp->sq_arg1, + sqp->sq_arg2); + sqp->sq_connvc->cvc_downcnt--; + } + + /* + * Dequeue processed entry and free it + */ + cnt++; + qnext = sqp->sq_next; + if (qprev) + qprev->sq_next = qnext; + else + atm_stackq_head = qnext; + if (qnext == NULL) + atm_stackq_tail = qprev; + atm_free((caddr_t)sqp); + sqp = qnext; + } + } while (cnt > 0); + + /* + * Make sure entire queue was drained + */ + if (atm_stackq_head != NULL) + panic("atm_stack_drain: Queue not emptied"); + + (void) splx(s); +} + + +/* + * Process Interrupt Queue + * + * Processes entries on the ATM interrupt queue. This queue is used by + * device interface drivers in order to schedule events from the driver's + * lower (interrupt) half to the driver's stack services. + * + * The interrupt routines must store the stack processing function to call + * and a token (typically a driver/stack control block) at the front of the + * queued buffer. We assume that the function pointer and token values are + * both contained (and properly aligned) in the first buffer of the chain. + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +atm_intr() +{ + KBuffer *m; + caddr_t cp; + atm_intr_func_t func; + void *token; + int s; + + for (; ; ) { + /* + * Get next buffer from queue + */ + s = splimp(); + IF_DEQUEUE(&atm_intrq, m); + (void) splx(s); + if (m == NULL) + break; + + /* + * Get function to call and token value + */ + KB_DATASTART(m, cp, caddr_t); + func = *(atm_intr_func_t *)cp; + cp += sizeof(func); + token = *(void **)cp; + KB_HEADADJ(m, -(sizeof(func) + sizeof(token))); + if (KB_LEN(m) == 0) { + KBuffer *m1; + KB_UNLINKHEAD(m, m1); + m = m1; + } + + /* + * Call processing function + */ + (*func)(token, m); + + /* + * Drain any deferred calls + */ + STACK_DRAIN(); + } +} + +#ifdef __FreeBSD__ +NETISR_SET(NETISR_ATM, atm_intr); +#endif + + +/* + * Print a pdu buffer chain + * + * Arguments: + * m pointer to pdu buffer chain + * msg pointer to message header string + * + * Returns: + * none + * + */ +void +atm_pdu_print(m, msg) + KBuffer *m; + char *msg; +{ + caddr_t cp; + int i; + char c = ' '; + + printf("%s:", msg); + while (m) { + KB_DATASTART(m, cp, caddr_t); + printf("%cbfr=0x%x data=0x%x len=%d: ", + c, (int)m, (int)cp, KB_LEN(m)); + c = '\t'; + if (atm_print_data) { + for (i = 0; i < KB_LEN(m); i++) { + printf("%2x ", (u_char)*cp++); + } + printf("<end_bfr>\n"); + } else { + printf("\n"); + } + m = KB_NEXT(m); + } +} + diff --git a/sys/netatm/atm_sys.h b/sys/netatm/atm_sys.h new file mode 100644 index 0000000..4cfb031 --- /dev/null +++ b/sys/netatm/atm_sys.h @@ -0,0 +1,275 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_sys.h,v 1.12 1998/05/18 19:05:57 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * General system definitions + * + */ + +#ifndef _NETATM_ATM_SYS_H +#define _NETATM_ATM_SYS_H + +/* + * Software Version + */ +#define ATM_VERSION 0x00030000 /* Version 3.0 */ +#define ATM_VERS_MAJ(v) ((v) >> 16) +#define ATM_VERS_MIN(v) ((v) & 0xffff) + + +/* + * Misc system defines + */ +#define ATM_CALLQ_MAX 100 /* Maximum length of call queue */ +#define ATM_INTRQ_MAX 1000 /* Maximum length of interrupt queue */ + + +/* + * ATM address manipulation macros + */ +#define ATM_ADDR_EQUAL(a1, a2) \ + (((a1)->address_format == (a2)->address_format) && \ + ((a1)->address_length == (a2)->address_length) && \ + (bcmp((caddr_t)(a1)->address, (caddr_t)(a2)->address, \ + (a1)->address_length) == 0)) + +#define ATM_ADDR_SEL_EQUAL(a1, s1, a2) \ + (((a1)->address_format == (a2)->address_format) && \ + ((a1)->address_length == (a2)->address_length) && \ + (((((a1)->address_format == T_ATM_ENDSYS_ADDR) || \ + ((a1)->address_format == T_ATM_NSAP_ADDR)) && \ + (bcmp((caddr_t)(a1)->address, (caddr_t)(a2)->address, \ + (a1)->address_length - 1) == 0) && \ + ((s1) == ((struct atm_addr_nsap *)(a2)->address)->aan_sel)) || \ + (((a1)->address_format != T_ATM_ENDSYS_ADDR) && \ + ((a1)->address_format != T_ATM_NSAP_ADDR) && \ + (bcmp((caddr_t)(a1)->address, (caddr_t)(a2)->address, \ + (a1)->address_length) == 0)))) + +#define ATM_ADDR_COPY(a1, a2) \ +{ \ + (a2)->address_format = (a1)->address_format; \ + (a2)->address_length = (a1)->address_length; \ + XM_COPY((caddr_t)(a1)->address, (caddr_t)(a2)->address, \ + (a1)->address_length); \ +} + +#define ATM_ADDR_SEL_COPY(a1, s1, a2) \ +{ \ + (a2)->address_format = (a1)->address_format; \ + (a2)->address_length = (a1)->address_length; \ + if (((a1)->address_format == T_ATM_ENDSYS_ADDR) || \ + ((a1)->address_format == T_ATM_NSAP_ADDR)) { \ + XM_COPY((caddr_t)(a1)->address, (caddr_t)(a2)->address, \ + (a1)->address_length - 1); \ + ((struct atm_addr_nsap *)(a2)->address)->aan_sel = (s1);\ + } else { \ + XM_COPY((caddr_t)(a1)->address, (caddr_t)(a2)->address, \ + (a1)->address_length); \ + } \ +} + + +/* + * ATM Cell Header definitions + */ + +/* + * These macros assume that the cell header (minus the HEC) + * is contained in the least-significant 32-bits of a word + */ +#define ATM_HDR_SET_VPI(vpi) (((vpi) & 0xff) << 20) +#define ATM_HDR_SET_VCI(vci) (((vci) & 0xffff) << 4) +#define ATM_HDR_SET_PT(pt) (((pt) & 0x7) << 1) +#define ATM_HDR_SET_CLP(clp) ((clp) & 0x1) +#define ATM_HDR_SET(vpi,vci,pt,clp) (ATM_HDR_SET_VPI(vpi) | \ + ATM_HDR_SET_VCI(vci) | \ + ATM_HDR_SET_PT(pt) | \ + ATM_HDR_SET_CLP(clp)) +#define ATM_HDR_GET_VPI(hdr) (((hdr) >> 20) & 0xff) +#define ATM_HDR_GET_VCI(hdr) (((hdr) >> 4) & 0xffff) +#define ATM_HDR_GET_PT(hdr) (((hdr) >> 1) & 0x7) +#define ATM_HDR_GET_CLP(hdr) ((hdr) & 0x1) + +/* + * Payload Type Identifier (3 bits) + */ +#define ATM_PT_USER_SDU0 0x0 /* User, no congestion, sdu type 0 */ +#define ATM_PT_USER_SDU1 0x1 /* User, no congestion, sdu type 1 */ +#define ATM_PT_USER_CONG_SDU0 0x2 /* User, congestion, sdu type 0 */ +#define ATM_PT_USER_CONG_SDU1 0x3 /* User, congestion, sdu type 1 */ +#define ATM_PT_NONUSER 0x4 /* User/non-user differentiator */ +#define ATM_PT_OAMF5_SEG 0x4 /* OAM F5 segment flow */ +#define ATM_PT_OAMF5_E2E 0x5 /* OAM F5 end-to-end flow */ + + +/* + * AAL (ATM Adaptation Layer) codes + */ +typedef u_char Aal_t; +#define ATM_AAL0 0 /* AAL0 - Cell service */ +#define ATM_AAL1 1 /* AAL1 */ +#define ATM_AAL2 2 /* AAL2 */ +#define ATM_AAL3_4 3 /* AAL3/4 */ +#define ATM_AAL5 5 /* AAL5 */ + + +/* + * VCC Encapsulation codes + */ +typedef u_char Encaps_t; +#define ATM_ENC_NULL 1 /* Null encapsulation */ +#define ATM_ENC_LLC 2 /* LLC encapsulation */ + + +#ifdef ATM_KERNEL +/* + * ATM timer control block. Used to schedule a timeout via atm_timeout(). + * This control block will typically be embedded in a processing-specific + * control block. + */ +struct atm_time { + u_short ti_ticks; /* Delta of ticks until timeout */ + u_char ti_flag; /* Timer flag bits (see below) */ + void (*ti_func) /* Call at timeout expiration */ + __P((struct atm_time *)); + struct atm_time *ti_next; /* Next on queue */ +}; + +/* + * Timer Flags + */ +#define TIF_QUEUED 0x01 /* Control block on timer queue */ + +#define ATM_HZ 2 /* Time ticks per second */ + + +/* + * To avoid heavy use of kmem_alloc, memory for protocol control blocks may + * be allocated from storage pools. Each control block type will have + * its own pool. Each storage pool will consist of individually allocated + * memory chunks, which will then be sub-divided into the separate control + * blocks. Each chunk will contain a header (sp_chunk) and 'n' blocks of the + * same type, plus a link field for each block. Each chunk will also contain + * a list of all free control blocks in the chunk. + * + * Each protocol must define an sp_info structure for each of its storage + * pools. This structure serves as the "root" for its particular pool. + * Protocols must not modify this structure after its first use. + */ +struct sp_info { + /* Values supplied by pool owner */ + char *si_name; /* Name of pool */ + size_t si_blksiz; /* Size of each block */ + int si_blkcnt; /* Blocks per chunk */ + int si_maxallow; /* Maximum allowable chunks */ + + /* Used by allocate/free functions - do not touch */ + struct sp_info *si_next; /* Next active storage pool */ + struct sp_chunk *si_poolh; /* Storage pool chunk head */ + struct sp_chunk *si_poolt; /* Storage pool chunk tail */ + size_t si_chunksiz; /* Size of chunk */ + int si_chunks; /* Current allocated chunks */ + int si_total; /* Total number of blocks */ + int si_free; /* Free blocks */ + int si_maxused; /* Maximum allocated chunks */ + int si_allocs; /* Total allocate calls */ + int si_fails; /* Allocate failures */ +}; + +struct sp_chunk { + struct sp_chunk *sc_next; /* Next chunk in pool */ + struct sp_info *sc_info; /* Storage pool info */ + u_int sc_magic; /* Chunk magic number */ + int sc_used; /* Allocated blocks in chunk */ + struct sp_link *sc_freeh; /* Head of free blocks in chunk */ + struct sp_link *sc_freet; /* Tail of free blocks in chunk */ +}; + +struct sp_link { + union { + struct sp_link *slu_next; /* Next block in free list */ + struct sp_chunk *slu_chunk; /* Link back to our chunk */ + } sl_u; +}; + +#define SPOOL_MAGIC 0x73d4b69c /* Storage pool magic number */ +#define SPOOL_MIN_CHUNK 2 /* Minimum number of chunks */ +#define SPOOL_ROUNDUP 16 /* Roundup for allocated chunks */ +#define SPOOL_COMPACT (300 * ATM_HZ) /* Compaction timeout value */ + +/* + * Debugging + */ +#ifdef DIAGNOSTIC +#define ATM_TIME \ + struct timeval now, delta; \ + KT_TIME(now); \ + delta.tv_sec = now.tv_sec - atm_debugtime.tv_sec; \ + delta.tv_usec = now.tv_usec - atm_debugtime.tv_usec; \ + atm_debugtime = now; \ + if (delta.tv_usec < 0) { \ + delta.tv_sec--; \ + delta.tv_usec += 1000000; \ + } \ + printf("%3d.%6d: ", delta.tv_sec, delta.tv_usec); + +#define ATM_DEBUG0(f) if (atm_debug) {ATM_TIME; printf(f);} +#define ATM_DEBUGN0(f) if (atm_debug) {printf(f);} +#define ATM_DEBUG1(f,a1) if (atm_debug) {ATM_TIME; printf(f, a1);} +#define ATM_DEBUGN1(f,a1) if (atm_debug) {printf(f, a1);} +#define ATM_DEBUG2(f,a1,a2) if (atm_debug) {ATM_TIME; printf(f, a1, a2);} +#define ATM_DEBUGN2(f,a1,a2) if (atm_debug) {printf(f, a1, a2);} +#define ATM_DEBUG3(f,a1,a2,a3) if (atm_debug) {ATM_TIME; printf(f, a1, a2, a3);} +#define ATM_DEBUGN3(f,a1,a2,a3) if (atm_debug) {printf(f, a1, a2, a3);} +#define ATM_DEBUG4(f,a1,a2,a3,a4) if (atm_debug) {ATM_TIME; printf(f, a1, a2, a3, a4);} +#define ATM_DEBUGN4(f,a1,a2,a3,a4) if (atm_debug) {printf(f, a1, a2, a3, a4);} +#define ATM_DEBUG5(f,a1,a2,a3,a4,a5) if (atm_debug) {ATM_TIME; printf(f, a1, a2, a3, a4, a5);} +#define ATM_DEBUGN5(f,a1,a2,a3,a4,a5) if (atm_debug) {printf(f, a1, a2, a3, a4, a5);} +#else +#define ATM_DEBUG0(f) +#define ATM_DEBUGN0(f) +#define ATM_DEBUG1(f,a1) +#define ATM_DEBUGN1(f,a1) +#define ATM_DEBUG2(f,a1,a2) +#define ATM_DEBUGN2(f,a1,a2) +#define ATM_DEBUG3(f,a1,a2,a3) +#define ATM_DEBUGN3(f,a1,a2,a3) +#define ATM_DEBUG4(f,a1,a2,a3,a4) +#define ATM_DEBUGN4(f,a1,a2,a3,a4) +#define ATM_DEBUG5(f,a1,a2,a3,a4,a5) +#define ATM_DEBUGN5(f,a1,a2,a3,a4,a5) +#endif + +#endif /* ATM_KERNEL */ + +#endif /* _NETATM_ATM_SYS_H */ diff --git a/sys/netatm/atm_usrreq.c b/sys/netatm/atm_usrreq.c new file mode 100644 index 0000000..4231d1c --- /dev/null +++ b/sys/netatm/atm_usrreq.c @@ -0,0 +1,711 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_usrreq.c,v 1.7 1998/06/29 21:51:29 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * ATM DGRAM socket protocol processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atm_usrreq.c,v 1.7 1998/06/29 21:51:29 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + + +/* + * Local functions + */ +static int atm_dgram_attach __P((struct socket *, int, struct proc *)); +static int atm_dgram_control __P((struct socket *, u_long, caddr_t, + struct ifnet *, struct proc *)); +static int atm_dgram_info __P((caddr_t)); + + +/* + * New-style socket request routines + */ +#if (defined(__FreeBSD__) && (BSD >= 199506)) +struct pr_usrreqs atm_dgram_usrreqs = { + atm_proto_notsupp1, /* pru_abort */ + pru_accept_notsupp, /* pru_accept */ + atm_dgram_attach, /* pru_attach */ + atm_proto_notsupp2, /* pru_bind */ + pru_connect_notsupp, /* pru_connect */ + pru_connect2_notsupp, /* pru_connect2 */ + atm_dgram_control, /* pru_control */ + atm_proto_notsupp1, /* pru_detach */ + atm_proto_notsupp1, /* pru_disconnect */ + pru_listen_notsupp, /* pru_listen */ + atm_proto_notsupp3, /* pru_peeraddr */ + pru_rcvd_notsupp, /* pru_rcvd */ + pru_rcvoob_notsupp, /* pru_rcvoob */ + atm_proto_notsupp4, /* pru_send */ + pru_sense_null, /* pru_sense */ + atm_proto_notsupp1, /* pru_shutdown */ + atm_proto_notsupp3, /* pru_sockaddr */ +}; +#endif + + +/* + * Handy common code macros + */ +#ifdef DIAGNOSTIC +#define ATM_INTRO() \ + int s, err = 0; \ + s = splnet(); \ + /* \ + * Stack queue should have been drained \ + */ \ + if (atm_stackq_head != NULL) \ + panic("atm_usrreq: stack queue not empty"); \ + ; +#else +#define ATM_INTRO() \ + int s, err = 0; \ + s = splnet(); \ + ; +#endif + +#define ATM_OUTRO() \ +done: \ + /* \ + * Drain any deferred calls \ + */ \ + STACK_DRAIN(); \ + (void) splx(s); \ + return (err); \ + ; + +#define ATM_RETERR(errno) { \ + err = errno; \ + goto done; \ +} + + +/* + * Attach protocol to socket + * + * Arguments: + * so pointer to socket + * proto protocol identifier + * p pointer to process + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_dgram_attach(so, proto, p) + struct socket *so; + int proto; + struct proc *p; +{ + ATM_INTRO(); + + /* + * Nothing to do here for ioctl()-only sockets + */ + ATM_OUTRO(); +} + + +/* + * Process ioctl system calls + * + * Arguments: + * so pointer to socket + * cmd ioctl code + * data pointer to code specific parameter data area + * ifp pointer to ifnet structure if it's an interface ioctl + * p pointer to process + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_dgram_control(so, cmd, data, ifp, p) + struct socket *so; + u_long cmd; + caddr_t data; + struct ifnet *ifp; + struct proc *p; +{ + ATM_INTRO(); + + /* + * First, figure out which ioctl we're dealing with and + * then process it based on the sub-op code + */ + switch (cmd) { + + case AIOCCFG: { + struct atmcfgreq *acp = (struct atmcfgreq *)data; + struct atm_pif *pip; + + if (p && (suser(p->p_ucred, &p->p_acflag) != 0)) + ATM_RETERR(EPERM); + + switch (acp->acr_opcode) { + + case AIOCS_CFG_ATT: + /* + * Attach signalling manager + */ + if ((pip = atm_pifname(acp->acr_att_intf)) == NULL) + ATM_RETERR(ENXIO); + err = atm_sigmgr_attach(pip, acp->acr_att_proto); + break; + + case AIOCS_CFG_DET: + /* + * Detach signalling manager + */ + if ((pip = atm_pifname(acp->acr_det_intf)) == NULL) + ATM_RETERR(ENXIO); + err = atm_sigmgr_detach(pip); + break; + + default: + err = EOPNOTSUPP; + } + break; + } + + case AIOCADD: { + struct atmaddreq *aap = (struct atmaddreq *)data; + Atm_endpoint *epp; + + if (p && (suser(p->p_ucred, &p->p_acflag) != 0)) + ATM_RETERR(EPERM); + + switch (aap->aar_opcode) { + + case AIOCS_ADD_PVC: + /* + * Add a PVC definition + */ + + /* + * Locate requested endpoint service + */ + epp = aap->aar_pvc_sap > ENDPT_MAX ? NULL : + atm_endpoints[aap->aar_pvc_sap]; + if (epp == NULL) + ATM_RETERR(ENOPROTOOPT); + + /* + * Let endpoint service handle it from here + */ + err = (*epp->ep_ioctl)(AIOCS_ADD_PVC, data, NULL); + break; + + case AIOCS_ADD_ARP: + /* + * Add an ARP mapping + */ + epp = atm_endpoints[ENDPT_IP]; + if (epp == NULL) + ATM_RETERR(ENOPROTOOPT); + + /* + * Let IP/ATM endpoint handle this + */ + err = (*epp->ep_ioctl) (AIOCS_ADD_ARP, data, NULL); + break; + + default: + err = EOPNOTSUPP; + } + break; + } + + case AIOCDEL: { + struct atmdelreq *adp = (struct atmdelreq *)data; + struct atm_pif *pip; + struct sigmgr *smp; + Atm_endpoint *epp; + + if (p && (suser(p->p_ucred, &p->p_acflag) != 0)) + ATM_RETERR(EPERM); + + switch (adp->adr_opcode) { + + case AIOCS_DEL_PVC: + case AIOCS_DEL_SVC: + /* + * Delete a PVC or SVC + */ + + /* + * Locate appropriate sigmgr + */ + if ((pip = atm_pifname(adp->adr_pvc_intf)) == NULL) + ATM_RETERR(ENXIO); + if ((smp = pip->pif_sigmgr) == NULL) + ATM_RETERR(ENOENT); + + /* + * Let sigmgr handle it from here + */ + err = (*smp->sm_ioctl)(adp->adr_opcode, data, + (caddr_t)pip->pif_siginst); + break; + + case AIOCS_DEL_ARP: + /* + * Delete an ARP mapping + */ + epp = atm_endpoints[ENDPT_IP]; + if (epp == NULL) + ATM_RETERR(ENOPROTOOPT); + + /* + * Let IP/ATM endpoint handle this + */ + err = (*epp->ep_ioctl) (AIOCS_DEL_ARP, data, NULL); + break; + + default: + err = EOPNOTSUPP; + } + break; + } + + case AIOCSET: { + struct atmsetreq *asp = (struct atmsetreq *)data; + struct atm_pif *pip; + struct atm_nif *nip; + struct sigmgr *smp; + struct ifnet *ifp2; + + if (p && (suser(p->p_ucred, &p->p_acflag) != 0)) + ATM_RETERR(EPERM); + + switch (asp->asr_opcode) { + + case AIOCS_SET_ASV: + /* + * Set an ARP server address + */ + + /* + * Locate appropriate sigmgr + */ + if ((nip = atm_nifname(asp->asr_arp_intf)) == NULL) + ATM_RETERR(ENXIO); + pip = nip->nif_pif; + if ((smp = pip->pif_sigmgr) == NULL) + ATM_RETERR(ENOENT); + + /* + * Let sigmgr handle it from here + */ + err = (*smp->sm_ioctl)(AIOCS_SET_ASV, data, + (caddr_t)nip); + break; + + case AIOCS_SET_MAC: + /* + * Set physical interface MAC/ESI address + */ + + /* + * Locate physical interface + */ + if ((pip = atm_pifname(asp->asr_mac_intf)) == NULL) + ATM_RETERR(ENXIO); + + /* + * Interface must be detached + */ + if (pip->pif_sigmgr != NULL) + ATM_RETERR(EADDRINUSE); + + /* + * Just plunk the address into the pif + */ + KM_COPY((caddr_t)&asp->asr_mac_addr, + (caddr_t)&pip->pif_macaddr, + sizeof(struct mac_addr)); + break; + + case AIOCS_SET_NIF: + /* + * Define network interfaces + */ + if ((pip = atm_pifname(asp->asr_nif_intf)) == NULL) + ATM_RETERR(ENXIO); + + /* + * Validate interface count - logical interfaces + * are differentiated by the atm address selector. + */ + if ((asp->asr_nif_cnt <= 0) || (asp->asr_nif_cnt > 256)) + ATM_RETERR(EINVAL); + + /* + * Make sure prefix name is unique + */ + TAILQ_FOREACH(ifp2, &ifnet, if_link) { + if (!strcmp(ifp2->if_name, asp->asr_nif_pref)) { + /* + * If this is for the interface we're + * (re-)defining, let it through + */ + for (nip = pip->pif_nif; nip; + nip = nip->nif_pnext) { + if (&nip->nif_if == ifp2) + break; + } + if (nip) + continue; + ATM_RETERR(EEXIST); + } + } + + /* + * Let interface handle it from here + */ + err = (*pip->pif_ioctl)(AIOCS_SET_NIF, data, + (caddr_t)pip); + break; + + case AIOCS_SET_PRF: + /* + * Set interface NSAP Prefix + */ + + /* + * Locate appropriate sigmgr + */ + if ((pip = atm_pifname(asp->asr_prf_intf)) == NULL) + ATM_RETERR(ENXIO); + if ((smp = pip->pif_sigmgr) == NULL) + ATM_RETERR(ENOENT); + + /* + * Let sigmgr handle it from here + */ + err = (*smp->sm_ioctl)(AIOCS_SET_PRF, data, + (caddr_t)pip->pif_siginst); + break; + + default: + err = EOPNOTSUPP; + } + break; + } + + case AIOCINFO: + err = atm_dgram_info(data); + break; + + default: + err = EOPNOTSUPP; + } + + ATM_OUTRO(); +} + + +/* + * Process AIOCINFO ioctl system calls + * + * Called at splnet. + * + * Arguments: + * data pointer to AIOCINFO parameter structure + * + * Returns: + * 0 request processed + * errno error processing request - reason indicated + * + */ +static int +atm_dgram_info(data) + caddr_t data; +{ + struct atminfreq *aip = (struct atminfreq *)data; + struct atm_pif *pip; + struct atm_nif *nip; + struct sigmgr *smp; + Atm_endpoint *epp; + int len = aip->air_buf_len; + int err = 0; + + switch (aip->air_opcode) { + + case AIOCS_INF_VST: + case AIOCS_INF_CFG: + /* + * Get vendor interface information + */ + if (aip->air_vinfo_intf[0] != '\0') { + /* + * Interface specified + */ + if ((pip = atm_pifname(aip->air_vinfo_intf))) { + err = (*pip->pif_ioctl)(aip->air_opcode, data, + (caddr_t)pip); + } else { + err = ENXIO; + } + } else { + /* + * Want info for every interface + */ + for (pip = atm_interface_head; pip; + pip = pip->pif_next) { + err = (*pip->pif_ioctl)(aip->air_opcode, data, + (caddr_t)pip); + if (err) + break; + } + } + break; + + case AIOCS_INF_IPM: + /* + * Get IP Map information + */ + epp = atm_endpoints[ENDPT_IP]; + if (epp) { + err = (*epp->ep_ioctl) (AIOCS_INF_IPM, data, NULL); + } else { + err = ENOPROTOOPT; + } + break; + + case AIOCS_INF_ARP: + /* + * Get ARP table information + */ + for (pip = atm_interface_head; pip; pip = pip->pif_next) { + if (smp = pip->pif_sigmgr) { + err = (*smp->sm_ioctl)(AIOCS_INF_ARP, + data, (caddr_t)pip->pif_siginst); + } + if (err) + break; + } + break; + + case AIOCS_INF_ASV: + /* + * Get ARP server information + */ + if (aip->air_asrv_intf[0] != '\0') { + /* + * Interface specified + */ + if ((nip = atm_nifname(aip->air_asrv_intf))) { + if (smp = nip->nif_pif->pif_sigmgr) { + err = (*smp->sm_ioctl)(AIOCS_INF_ASV, + data, (caddr_t)nip); + } + } else { + err = ENXIO; + } + } else { + /* + * Want info for all arp servers + */ + for (pip = atm_interface_head; pip; + pip = pip->pif_next) { + if (smp = pip->pif_sigmgr) { + err = (*smp->sm_ioctl)(AIOCS_INF_ASV, + data, NULL); + } + if (err) + break; + } + } + break; + + case AIOCS_INF_INT: + /* + * Get physical interface info + */ + if (aip->air_int_intf[0] != '\0') { + /* + * Interface specified + */ + if ((pip = atm_pifname(aip->air_int_intf))) { + err = (*pip->pif_ioctl)(AIOCS_INF_INT, + data, (caddr_t)pip); + } else { + err = ENXIO; + } + } else { + /* + * Want info for every physical interface + */ + for (pip = atm_interface_head; pip; + pip = pip->pif_next) { + err = (*pip->pif_ioctl)(AIOCS_INF_INT, + data, (caddr_t)pip); + if (err) + break; + } + } + break; + + case AIOCS_INF_VCC: + /* + * Get VCC information + */ + if (aip->air_vcc_intf[0] != '\0') { + /* + * Interface specified + */ + if ((pip = atm_pifname(aip->air_vcc_intf))) { + if (smp = pip->pif_sigmgr) { + err = (*smp->sm_ioctl)(AIOCS_INF_VCC, + data, + (caddr_t)pip->pif_siginst); + } + } else { + err = ENXIO; + } + } else { + /* + * Want info for every interface + */ + for (pip = atm_interface_head; pip; + pip = pip->pif_next) { + if (smp = pip->pif_sigmgr) { + err = (*smp->sm_ioctl)(AIOCS_INF_VCC, + data, + (caddr_t)pip->pif_siginst); + } + if (err) + break; + } + } + break; + + case AIOCS_INF_NIF: + /* + * Get network interface info + */ + if (aip->air_int_intf[0] != '\0') { + /* + * Interface specified + */ + if ((nip = atm_nifname(aip->air_int_intf))) { + pip = nip->nif_pif; + err = (*pip->pif_ioctl)(AIOCS_INF_NIF, + data, (caddr_t)nip); + } else { + err = ENXIO; + } + } else { + /* + * Want info for every network interface + */ + for (pip = atm_interface_head; pip; + pip = pip->pif_next) { + for (nip = pip->pif_nif; nip; + nip = nip->nif_pnext) { + err = (*pip->pif_ioctl)(AIOCS_INF_NIF, + data, (caddr_t)nip); + if (err) + break; + } + if (err) + break; + } + } + break; + + case AIOCS_INF_PIS: + /* + * Get physical interface statistics + */ + if (aip->air_physt_intf[0] != '\0') { + /* + * Interface specified + */ + if ((pip = atm_pifname(aip->air_physt_intf))) { + err = (*pip->pif_ioctl)(AIOCS_INF_PIS, + data, (caddr_t)pip); + } else { + err = ENXIO; + } + } else { + /* + * Want statistics for every physical interface + */ + for (pip = atm_interface_head; pip; + pip = pip->pif_next) { + err = (*pip->pif_ioctl)(AIOCS_INF_PIS, + data, (caddr_t)pip); + if (err) + break; + } + } + break; + + case AIOCS_INF_VER: + /* + * Get ATM software version + */ + if (len < sizeof(atm_version)) { + err = ENOSPC; + break; + } + if (err = copyout((caddr_t)&atm_version, + aip->air_buf_addr, + sizeof(atm_version))) { + break; + } + aip->air_buf_addr += sizeof(atm_version); + aip->air_buf_len -= sizeof(atm_version); + break; + + default: + err = EOPNOTSUPP; + } + + /* + * Calculate returned buffer length + */ + aip->air_buf_len = len - aip->air_buf_len; + + return (err); +} + diff --git a/sys/netatm/atm_var.h b/sys/netatm/atm_var.h new file mode 100644 index 0000000..ab5f856 --- /dev/null +++ b/sys/netatm/atm_var.h @@ -0,0 +1,208 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_var.h,v 1.9 1998/05/18 19:05:52 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * ATM system variables + * + */ + +#ifndef _NETATM_ATM_VAR_H +#define _NETATM_ATM_VAR_H + + +#ifdef ATM_KERNEL +/* + * Global variable declarations + */ + /* atm_aal5.c */ +#if (defined(__FreeBSD__) && (BSD >= 199506)) +extern struct pr_usrreqs atm_aal5_usrreqs; +#endif + + /* atm_proto.c */ +extern struct domain atmdomain; + + /* atm_subr.c */ +extern struct atm_pif *atm_interface_head; +extern struct atm_ncm *atm_netconv_head; +extern Atm_endpoint *atm_endpoints[]; +extern struct sp_info *atm_pool_head; +extern struct stackq_entry *atm_stackq_head; +extern struct stackq_entry *atm_stackq_tail; +extern struct ifqueue atm_intrq; +#ifdef sgi +extern int atm_intr_index; +#endif +extern struct atm_sock_stat atm_sock_stat; +extern int atm_init; +extern int atm_version; +extern int atm_debug; +extern struct timeval atm_debugtime; +extern int atm_dev_print; +extern int atm_print_data; +extern struct sp_info atm_attributes_pool; + + /* atm_usrreq.c */ +#if (defined(__FreeBSD__) && (BSD >= 199506)) +extern struct pr_usrreqs atm_dgram_usrreqs; +#endif + + +/* + * Global function declarations + */ + /* atm_aal5.c */ +int atm_aal5_ctloutput __P((struct socket *, struct sockopt *)); +void atm_aal5_init __P((void)); + + /* atm_cm.c */ +int atm_cm_connect __P((Atm_endpoint *, void *, Atm_attributes *, + Atm_connection **)); +int atm_cm_listen __P((Atm_endpoint *, void *, Atm_attributes *, + Atm_connection **)); +int atm_cm_addllc __P((Atm_endpoint *, void *, struct attr_llc *, + Atm_connection *, Atm_connection **)); +int atm_cm_addparty __P((Atm_connection *, int, + struct t_atm_sap *)); +int atm_cm_dropparty __P((Atm_connection *, int, + struct t_atm_cause *)); +int atm_cm_release __P((Atm_connection *, struct t_atm_cause *)); +int atm_cm_abort __P((Atm_connvc *, struct t_atm_cause *)); +int atm_cm_incoming __P((struct vccb *, Atm_attributes *)); +void atm_cm_connected __P((Atm_connvc *)); +void atm_cm_cleared __P((Atm_connvc *)); +Atm_connection *atm_cm_match __P((Atm_attributes *, Atm_connection *)); +int atm_cm_cpcs_ctl __P((int, Atm_connection *, void *)); +int atm_cm_cpcs_data __P((Atm_connection *, KBuffer *)); +int atm_cm_saal_ctl __P((int, Atm_connection *, void *)); +int atm_cm_saal_data __P((Atm_connection *, KBuffer *)); +int atm_cm_sscop_ctl __P((int, Atm_connection *, void *, void *)); +int atm_cm_sscop_data __P((Atm_connection *, KBuffer *)); +int atm_endpoint_register __P((Atm_endpoint *)); +int atm_endpoint_deregister __P((Atm_endpoint *)); + + /* atm_device.c */ +int atm_dev_inst __P((struct stack_defn **, Atm_connvc *)); +void atm_dev_lower __P((int, void *, int, int)); +void * atm_dev_alloc __P((u_int, u_int, u_int)); +void atm_dev_free __P((void *)); +#if defined(sun4m) +void * atm_dma_map __P((caddr_t, int, int)); +void atm_dma_free __P((caddr_t, int)); +#endif +KBuffer * atm_dev_compress __P((KBuffer *)); +Cmn_vcc * atm_dev_vcc_find __P((Cmn_unit *, u_int, u_int, u_int)); +void atm_dev_pdu_print __P((Cmn_unit *, Cmn_vcc *, KBuffer *, + char *)); + + /* atm_if.c */ +int atm_physif_register __P((Cmn_unit *, char *, + struct stack_defn *)); +int atm_physif_deregister __P((Cmn_unit *)); +void atm_physif_freenifs __P((struct atm_pif *)); +int atm_netconv_register __P((struct atm_ncm *)); +int atm_netconv_deregister __P((struct atm_ncm *)); +int atm_nif_attach __P((struct atm_nif *)); +void atm_nif_detach __P((struct atm_nif *)); +int atm_nif_setaddr __P((struct atm_nif *, struct ifaddr *)); +#if (defined(BSD) && (BSD >= 199103)) +int atm_ifoutput __P((struct ifnet *, KBuffer *, + struct sockaddr *, struct rtentry *)); +#else +int atm_ifoutput __P((struct ifnet *, KBuffer *, + struct sockaddr *)); +#endif +struct atm_pif * + atm_pifname __P((char *)); +struct atm_nif * + atm_nifname __P((char *)); + + /* atm_proto.c */ +#if (defined(__FreeBSD__) && (BSD >= 199506)) +int atm_proto_notsupp1 __P((struct socket *)); +int atm_proto_notsupp2 __P((struct socket *, struct sockaddr *, + struct proc *)); +int atm_proto_notsupp3 __P((struct socket *, struct sockaddr **)); +int atm_proto_notsupp4 __P((struct socket *, int, KBuffer *, + struct sockaddr *, KBuffer *, struct proc *)); +#endif + + /* atm_signal.c */ +int atm_sigmgr_register __P((struct sigmgr *)); +int atm_sigmgr_deregister __P((struct sigmgr *)); +int atm_sigmgr_attach __P((struct atm_pif *, u_char)); +int atm_sigmgr_detach __P((struct atm_pif *)); +int atm_stack_register __P((struct stack_defn *)); +int atm_stack_deregister __P((struct stack_defn *)); +int atm_create_stack __P((Atm_connvc *, struct stack_list *, + void (*)__P((int, void *, int, int)) )); + + /* atm_socket.c */ +int atm_sock_attach __P((struct socket *, u_long, u_long)); +int atm_sock_detach __P((struct socket *)); +int atm_sock_bind __P((struct socket *, struct sockaddr *)); +int atm_sock_listen __P((struct socket *, Atm_endpoint *)); +int atm_sock_connect __P((struct socket *, struct sockaddr *, + Atm_endpoint *)); +int atm_sock_disconnect __P((struct socket *)); +int atm_sock_sockaddr __P((struct socket *, struct sockaddr **)); +int atm_sock_peeraddr __P((struct socket *, struct sockaddr **)); +int atm_sock_setopt __P((struct socket *, struct sockopt *, + Atm_pcb *)); +int atm_sock_getopt __P((struct socket *, struct sockopt *, + Atm_pcb *)); +void atm_sock_connected __P((void *)); +void atm_sock_cleared __P((void *, struct t_atm_cause *)); + + /* atm_subr.c */ +void atm_initialize __P((void)); +void * atm_allocate __P((struct sp_info *)); +void atm_free __P((void *)); +void atm_release_pool __P((struct sp_info *)); +void atm_timeout __P((struct atm_time *, int, + void (*) __P((struct atm_time *)) )); +int atm_untimeout __P((struct atm_time *)); +int atm_stack_enq __P((int, void (*) __P((int, void *, int, int)), + void *, Atm_connvc *, int, int)); +void atm_stack_drain __P((void)); +void atm_intr __P((void)); +void atm_pdu_print __P((KBuffer *, char *)); + + /* atm_usrreq.c */ +#if (!(defined(__FreeBSD__) && (BSD >= 199506))) +int atm_dgram_usrreq __P((struct socket *, int, KBuffer *, + KBuffer *, KBuffer *)); +#endif + +#endif /* ATM_KERNEL */ + +#endif /* _NETATM_ATM_VAR_H */ diff --git a/sys/netatm/atm_vc.h b/sys/netatm/atm_vc.h new file mode 100644 index 0000000..1c7c7b0 --- /dev/null +++ b/sys/netatm/atm_vc.h @@ -0,0 +1,89 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atm_vc.h,v 1.6 1998/02/19 20:00:34 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * ATM Virtual Channel definitions + * + */ + +#ifndef _NETATM_ATM_VC_H +#define _NETATM_ATM_VC_H + + +#ifdef ATM_KERNEL +/* + * ATM Virtual Channel Connection control block. All vccb's are created + * and controlled by an ATM signalling manager. Each ATM signalling + * protocol will also have its own protocol-specific vccb format. Each + * of these protocol vccb's must have this common block at the beginning. + */ +struct vccb { + u_char vc_type; /* VCC type (see below) */ + u_char vc_proto; /* Signalling protocol */ + u_char vc_sstate; /* Signalling state (sigmgr specific) */ + u_char vc_ustate; /* User interface state (see below) */ + struct atm_pif *vc_pif; /* Physical interface */ + struct atm_nif *vc_nif; /* Network interface */ + Qelem_t vc_sigelem; /* Signalling instance vccb queue */ + struct atm_time vc_time; /* Timer controls */ + u_short vc_vpi; /* Virtual Path Identifier */ + u_short vc_vci; /* Virtual Channel Identifier */ + Atm_connvc *vc_connvc; /* CM connection VCC instance */ + long vc_ipdus; /* PDUs received from VCC */ + long vc_opdus; /* PDUs sent to VCC */ + long vc_ibytes; /* Bytes received from VCC */ + long vc_obytes; /* Bytes sent to VCC */ + long vc_ierrors; /* Errors receiving from VCC */ + long vc_oerrors; /* Errors sending to VCC */ + time_t vc_tstamp; /* State transition timestamp */ +}; +#endif /* ATM_KERNEL */ + +/* + * VCC Types + */ +#define VCC_PVC 0x01 /* PVC (Permanent Virtual Channel) */ +#define VCC_SVC 0x02 /* SVC (Switched Virtual Channel) */ +#define VCC_IN 0x04 /* Inbound VCC */ +#define VCC_OUT 0x08 /* Outbound VCC */ + +/* + * VCC Signalling-to-User Interface States + */ +#define VCCU_NULL 0 /* No state */ +#define VCCU_POPEN 1 /* Pending open completion */ +#define VCCU_OPEN 2 /* Connection is open */ +#define VCCU_CLOSED 3 /* Connection has been terminated */ +#define VCCU_ABORT 4 /* Connection being aborted */ + + +#endif /* _NETATM_ATM_VC_H */ diff --git a/sys/netatm/ipatm/ipatm.h b/sys/netatm/ipatm/ipatm.h new file mode 100644 index 0000000..b3ce348 --- /dev/null +++ b/sys/netatm/ipatm/ipatm.h @@ -0,0 +1,55 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: ipatm.h,v 1.5 1998/03/24 20:49:49 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * Protocol definitions + * + */ + +#ifndef _IPATM_IPATM_H +#define _IPATM_IPATM_H + +/* + * Protocol Variables + */ +#define IPATM_VCIDLE 15 /* VCC idle time (minutes) */ +#define IPATM_ARP_TIME (60 * ATM_HZ) /* Wait for ARP answer */ +#define IPATM_SVC_TIME (60 * ATM_HZ) /* Wait for SVC open answer */ +#define IPATM_IDLE_TIME (60 * ATM_HZ) /* VCC idle timer tick */ + +/* + * IP/ATM LLC/SNAP header + */ +#define IPATM_LLC_LEN 8 +#define IPATM_LLC_HDR {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00} + +#endif /* _IPATM_IPATM_H */ diff --git a/sys/netatm/ipatm/ipatm_event.c b/sys/netatm/ipatm/ipatm_event.c new file mode 100644 index 0000000..048edf9 --- /dev/null +++ b/sys/netatm/ipatm/ipatm_event.c @@ -0,0 +1,454 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: ipatm_event.c,v 1.8 1998/08/06 18:21:13 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * IP VCC event handler + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: ipatm_event.c,v 1.8 1998/08/06 18:21:13 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm.h> +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> + + +/* + * Process an IP VCC timeout + * + * Called when a previously scheduled ipvcc control block timer expires. + * Processing will be based on the current ipvcc state. + * + * Called at splnet. + * + * Arguments: + * tip pointer to ipvcc timer control block + * + * Returns: + * none + * + */ +void +ipatm_timeout(tip) + struct atm_time *tip; +{ + struct ipvcc *ivp; + + /* + * Back-off to ipvcc control block + */ + ivp = (struct ipvcc *) + ((caddr_t)tip - (int)(&((struct ipvcc *)0)->iv_time)); + + /* + * Process timeout based on protocol state + */ + switch (ivp->iv_state) { + + case IPVCC_PMAP: + /* + * Give up waiting for arp response + */ + (void) ipatm_closevc(ivp, T_ATM_CAUSE_TEMPORARY_FAILURE); + break; + + case IPVCC_POPEN: + case IPVCC_PACCEPT: + /* + * Give up waiting for signalling manager response + */ + (void) ipatm_closevc(ivp, T_ATM_CAUSE_TEMPORARY_FAILURE); + break; + + case IPVCC_ACTPENT: + /* + * Try again to get an ARP entry + */ + switch ((*ivp->iv_ipnif->inf_serv->is_arp_pvcopen)(ivp)) { + + case MAP_PROCEEDING: + /* + * Wait for answer + */ + ivp->iv_state = IPVCC_ACTIVE; + break; + + case MAP_VALID: + /* + * We've got our answer already + */ + ivp->iv_state = IPVCC_ACTIVE; + ivp->iv_flags |= IVF_MAPOK; + ivp->iv_dst.s_addr = ivp->iv_arpent->am_dstip.s_addr; + break; + + case MAP_FAILED: + /* + * Try again later + */ + IPVCC_TIMER(ivp, 5 * ATM_HZ); + break; + + default: + panic("ipatm_timeout: invalid am_pvcopen return"); + } + break; + + default: + log(LOG_ERR, "ipatm: invalid timer state: ivp=0x%x, state=%d\n", + (int)ivp, ivp->iv_state); + } +} + + +/* + * Process IP VCC Connected Notification + * + * Arguments: + * toku owner's connection token (ipvcc protocol block) + * + * Returns: + * none + * + */ +void +ipatm_connected(toku) + void *toku; +{ + struct ipvcc *ivp = (struct ipvcc *)toku; + + /* + * SVC is connected + */ + if ((ivp->iv_state != IPVCC_POPEN) && + (ivp->iv_state != IPVCC_PACCEPT)) { + log(LOG_ERR, "ipatm: invalid CALL_CONNECTED state=%d\n", + ivp->iv_state); + return; + } + + /* + * Verify possible negotiated parameter values + */ + if (ivp->iv_state == IPVCC_POPEN) { + Atm_attributes *ap = &ivp->iv_conn->co_connvc->cvc_attr; + int mtu = (ivp->iv_flags & IVF_LLC) ? + ATM_NIF_MTU + IPATM_LLC_LEN : + ATM_NIF_MTU; + + /* + * Verify final MTU + */ + if (ap->aal.type == ATM_AAL5) { + if ((ap->aal.v.aal5.forward_max_SDU_size < mtu) || + (ap->aal.v.aal5.backward_max_SDU_size > mtu)) { + (void) ipatm_closevc(ivp, + T_ATM_CAUSE_AAL_PARAMETERS_NOT_SUPPORTED); + return; + } + } else { + if ((ap->aal.v.aal4.forward_max_SDU_size < mtu) || + (ap->aal.v.aal4.backward_max_SDU_size > mtu)) { + (void) ipatm_closevc(ivp, + T_ATM_CAUSE_AAL_PARAMETERS_NOT_SUPPORTED); + return; + } + } + } + + /* + * Finish up VCC activation + */ + ipatm_activate(ivp); +} + + +/* + * Process IP VCC Cleared Notification + * + * Arguments: + * toku owner's connection token (ipvcc protocol block) + * cause pointer to cause code + * + * Returns: + * none + * + */ +void +ipatm_cleared(toku, cause) + void *toku; + struct t_atm_cause *cause; +{ + struct ipvcc *ivp = (struct ipvcc *)toku; + + + /* + * VCC has been cleared, so figure out what's next + */ + ivp->iv_conn = NULL; + + switch (ivp->iv_state) { + + case IPVCC_POPEN: + /* + * Call setup failed, see if there is another + * set of vcc parameters to try + */ + ivp->iv_state = IPVCC_CLOSED; + if (ipatm_retrysvc(ivp)) { + (void) ipatm_closevc(ivp, cause->cause_value); + } + break; + + case IPVCC_PACCEPT: + case IPVCC_ACTPENT: + case IPVCC_ACTIVE: + ivp->iv_state = IPVCC_CLOSED; + (void) ipatm_closevc(ivp, cause->cause_value); + break; + } +} + + +/* + * Process an ARP Event Notification + * + * Arguments: + * ivp pointer to IP VCC control block + * event ARP event type + * + * Returns: + * none + * + */ +void +ipatm_arpnotify(ivp, event) + struct ipvcc *ivp; + int event; +{ + struct sockaddr_in sin; + struct ifnet *ifp; + + /* + * Process event + */ + switch (event) { + + case MAP_VALID: + switch (ivp->iv_state) { + + case IPVCC_PMAP: + /* + * We've got our destination, however, first we'll + * check to make sure no other VCC to our destination + * has also had it's ARP table entry completed. + * If we don't find a better VCC to use, then we'll + * go ahead and open this SVC. + */ + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = ivp->iv_dst.s_addr; + if (ipatm_iptovc(&sin, ivp->iv_ipnif->inf_nif) != ivp) { + /* + * We found a better VCC, so use it and + * get rid of this VCC + */ + if (ivp->iv_queue) { + ifp = (struct ifnet *) + ivp->iv_ipnif->inf_nif; + (void) ipatm_ifoutput(ifp, + ivp->iv_queue, + (struct sockaddr *)&sin); + ivp->iv_queue = NULL; + } + (void) ipatm_closevc(ivp, + T_ATM_CAUSE_UNSPECIFIED_NORMAL); + + } else { + /* + * We like this VCC... + */ + ivp->iv_flags |= IVF_MAPOK; + if (ipatm_opensvc(ivp)) { + (void) ipatm_closevc(ivp, + T_ATM_CAUSE_TEMPORARY_FAILURE); + } + } + break; + + case IPVCC_POPEN: + case IPVCC_PACCEPT: + case IPVCC_ACTIVE: + /* + * Everything looks good, so accept new mapping + */ + ivp->iv_flags |= IVF_MAPOK; + ivp->iv_dst.s_addr = ivp->iv_arpent->am_dstip.s_addr; + + /* + * Send queued packet + */ + if ((ivp->iv_state == IPVCC_ACTIVE) && ivp->iv_queue) { + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = ivp->iv_dst.s_addr; + ifp = (struct ifnet *)ivp->iv_ipnif->inf_nif; + (void) ipatm_ifoutput(ifp, ivp->iv_queue, + (struct sockaddr *)&sin); + ivp->iv_queue = NULL; + } + break; + } + break; + + case MAP_INVALID: + switch (ivp->iv_state) { + + case IPVCC_POPEN: + case IPVCC_PACCEPT: + case IPVCC_ACTIVE: + + /* + * Mapping has gone stale, so we cant use this VCC + * until the mapping is refreshed + */ + ivp->iv_flags &= ~IVF_MAPOK; + break; + } + break; + + case MAP_FAILED: + /* + * ARP lookup failed, just trash it all + */ + (void) ipatm_closevc(ivp, T_ATM_CAUSE_TEMPORARY_FAILURE); + break; + + case MAP_CHANGED: + /* + * ARP mapping has changed + */ + if (ivp->iv_flags & IVF_PVC) { + /* + * For PVCs, just reset lookup cache if needed + */ + if (last_map_ipvcc == ivp) { + last_map_ipdst = 0; + last_map_ipvcc = NULL; + } + } else { + /* + * Close SVC if it has already used this mapping + */ + switch (ivp->iv_state) { + + case IPVCC_POPEN: + case IPVCC_ACTIVE: + (void) ipatm_closevc(ivp, + T_ATM_CAUSE_UNSPECIFIED_NORMAL); + break; + } + } + break; + + default: + log(LOG_ERR, "ipatm: unknown arp event %d, ivp=0x%x\n", + event, (int)ivp); + } +} + + +/* + * Process an IP VCC idle timer tick + * + * This function is called every IPATM_IDLE_TIME seconds, in order to + * scan for idle IP VCC's. If an active VCC reaches the idle time limit, + * then it will be closed. + * + * Called at splnet. + * + * Arguments: + * tip pointer to the VCC idle timer control block + * + * Returns: + * none + * + */ +void +ipatm_itimeout(tip) + struct atm_time *tip; +{ + struct ipvcc *ivp, *inext; + struct ip_nif *inp; + + + /* + * Schedule next timeout + */ + atm_timeout(&ipatm_itimer, IPATM_IDLE_TIME, ipatm_itimeout); + + /* + * Check for disabled idle timeout + */ + if (ipatm_vcidle == 0) + return; + + /* + * Check out all IP VCCs + */ + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp; + ivp = inext) { + + inext = Q_NEXT(ivp, struct ipvcc, iv_elem); + + /* + * Looking for active, idle SVCs + */ + if (ivp->iv_flags & (IVF_PVC | IVF_NOIDLE)) + continue; + if (ivp->iv_state != IPVCC_ACTIVE) + continue; + if (++ivp->iv_idle < ipatm_vcidle) + continue; + + /* + * OK, we found one - close the VCC + */ + (void) ipatm_closevc(ivp, + T_ATM_CAUSE_UNSPECIFIED_NORMAL); + } + } +} + diff --git a/sys/netatm/ipatm/ipatm_if.c b/sys/netatm/ipatm/ipatm_if.c new file mode 100644 index 0000000..ede2450 --- /dev/null +++ b/sys/netatm/ipatm/ipatm_if.c @@ -0,0 +1,335 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: ipatm_if.c,v 1.6 1998/03/24 20:51:47 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * Interface Manager + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: ipatm_if.c,v 1.6 1998/03/24 20:51:47 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm.h> +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> + + +/* + * Local functions + */ +static void ipatm_closenif __P((struct ip_nif *)); + + +/* + * Process Network Interface status change + * + * Called whenever a network interface status change is requested. + * + * Called at splnet. + * + * Arguments: + * cmd command code + * nip pointer to atm network interface control block + * arg command specific parameter + * + * Returns: + * 0 command successful + * errno command failed - reason indicated + * + */ +int +ipatm_nifstat(cmd, nip, arg) + int cmd; + struct atm_nif *nip; + int arg; +{ + struct in_ifaddr *ia; + struct siginst *sip; + struct ip_nif *inp; + int err = 0; + + /* + * Look for corresponding IP interface + */ + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (inp->inf_nif == nip) + break; + } + + /* + * Process command + */ + switch (cmd) { + + case NCM_ATTACH: + /* + * Make sure i/f isn't already attached + */ + if (inp != NULL) { + err = EEXIST; + break; + } + + /* + * Get a new interface block + */ + inp = (struct ip_nif *)atm_allocate(&ipatm_nifpool); + if (inp == NULL) { + err = ENOMEM; + break; + } + inp->inf_nif = nip; + inp->inf_state = IPNIF_ADDR; + inp->inf_arpnotify = ipatm_arpnotify; + inp->inf_ipinput = ipatm_ipinput; + inp->inf_createsvc = ipatm_createsvc; + LINK2TAIL(inp, struct ip_nif, ipatm_nif_head, inf_next); + break; + + case NCM_DETACH: + /* + * Make sure i/f is attached + */ + if (inp == NULL) { + err = ENODEV; + break; + } + + /* + * Validate interface stuff + */ + if (Q_HEAD(inp->inf_vcq, struct ipvcc)) + panic("ipatm_nifstat: ipvcc queue not empty"); + + /* + * If we're active, close all our VCCs and tell the + * interface service about the deactivation + */ + if (inp->inf_state == IPNIF_ACTIVE) { + + ipatm_closenif(inp); + + if (inp->inf_serv) + (void) (*inp->inf_serv->is_ifdact)(inp); + } + + /* + * Clean up and free block + */ + UNLINK(inp, struct ip_nif, ipatm_nif_head, inf_next); + atm_free((caddr_t)inp); + break; + + case NCM_SETADDR: + /* + * We only care about IP addresses + */ +#if (defined(BSD) && (BSD >= 199103)) + if (((struct ifaddr *)arg)->ifa_addr->sa_family != AF_INET) +#else + if (((struct ifaddr *)arg)->ifa_addr.sa_family != AF_INET) +#endif + break; + + /* + * Make sure i/f is there + */ + ia = (struct in_ifaddr *)arg; + if (inp == NULL) + panic("ipatm_nifstat: setaddr missing ip_nif"); + + /* + * Process new address + */ + switch (inp->inf_state) { + + case IPNIF_SIGMGR: + case IPNIF_ADDR: + inp->inf_addr = ia; + + /* + * If signalling manager is not set, wait for it + */ + sip = nip->nif_pif->pif_siginst; + if (sip == NULL) { + inp->inf_state = IPNIF_SIGMGR; + break; + } + + /* + * Otherwise, everything's set + */ + inp->inf_state = IPNIF_ACTIVE; + + /* + * Tell interface service we're around + */ + if (sip->si_ipserv) { + inp->inf_serv = sip->si_ipserv; + err = (*inp->inf_serv->is_ifact)(inp); + } + + /* + * Reset state if there's been a problem + */ + if (err) { + inp->inf_serv = NULL; + inp->inf_addr = NULL; + inp->inf_state = IPNIF_ADDR; + } + break; + + case IPNIF_ACTIVE: + /* + * We dont support an address change + */ + err = EEXIST; + break; + } + break; + + case NCM_SIGATTACH: + /* + * Make sure i/f is attached + */ + if (inp == NULL) { + err = ENODEV; + break; + } + + /* + * Are we waiting for the sigmgr attach?? + */ + if (inp->inf_state != IPNIF_SIGMGR) { + /* + * No, nothing else to do + */ + break; + } + + /* + * OK, everything's set + */ + inp->inf_state = IPNIF_ACTIVE; + + /* + * Tell interface service we're around + */ + sip = nip->nif_pif->pif_siginst; + if (sip->si_ipserv) { + inp->inf_serv = sip->si_ipserv; + err = (*inp->inf_serv->is_ifact)(inp); + } + + /* + * Just report any problems, since a NCM_SIGDETACH will + * be coming down immediately + */ + break; + + case NCM_SIGDETACH: + /* + * Make sure i/f is attached + */ + if (inp == NULL) { + err = ENODEV; + break; + } + + /* + * Are we currently active?? + */ + if (inp->inf_state != IPNIF_ACTIVE) { + /* + * No, nothing else to do + */ + break; + } + + /* + * Close all the IP VCCs for this interface + */ + ipatm_closenif(inp); + + /* + * Tell interface service that i/f has gone down + */ + if (inp->inf_serv) + (void) (*inp->inf_serv->is_ifdact)(inp); + + /* + * Just have to wait for another sigattach + */ + inp->inf_serv = NULL; + inp->inf_state = IPNIF_SIGMGR; + break; + + default: + log(LOG_ERR, "ipatm_nifstat: unknown command %d\n", cmd); + } + + return (err); +} + + +/* + * Close all VCCs on a Network Interface + * + * Called at splnet. + * + * Arguments: + * inp pointer to IP network interface + * + * Returns: + * none + * + */ +static void +ipatm_closenif(inp) + struct ip_nif *inp; +{ + struct ipvcc *ivp, *inext; + + /* + * Close each IP VCC on this interface + */ + for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp; ivp = inext) { + + inext = Q_NEXT(ivp, struct ipvcc, iv_elem); + + (void) ipatm_closevc(ivp, T_ATM_CAUSE_UNSPECIFIED_NORMAL); + } +} + diff --git a/sys/netatm/ipatm/ipatm_input.c b/sys/netatm/ipatm/ipatm_input.c new file mode 100644 index 0000000..ca3e3e7 --- /dev/null +++ b/sys/netatm/ipatm/ipatm_input.c @@ -0,0 +1,210 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: ipatm_input.c,v 1.9 1998/04/07 23:03:52 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * Process stack and data input + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: ipatm_input.c,v 1.9 1998/04/07 23:03:52 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm.h> +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> + + +/* + * Process VCC Input Data + * + * Arguments: + * tok ipatm connection token (pointer to ipvcc) + * m pointer to input packet buffer chain + * + * Returns: + * none + * + */ +void +ipatm_cpcs_data(tok, m) + void *tok; + KBuffer *m; +{ + struct ipvcc *ivp = tok; + +#ifdef DIAGNOSTIC + if (ipatm_print) { + atm_pdu_print(m, "ipatm_input"); + } +#endif + + /* + * Handle input packet + */ + if (ivp->iv_state != IPVCC_ACTIVE) { + KB_FREEALL(m); + ipatm_stat.ias_rcvstate++; + return; + } + + /* + * IP packet - reset idle timer + */ + ivp->iv_idle = 0; + + /* + * Pass packet to IP + */ + (void) ipatm_ipinput(ivp->iv_ipnif, m); +} + + +/* + * IP Input Packet Handler + * + * All IP packets received from various ATM sources will be sent here + * for final queuing to the IP layer. + * + * Arguments: + * inp pointer to packet's receiving IP network interface + * m pointer to packet buffer chain + * + * Returns: + * 0 packet successfully queued to IP layer + * else error queuing packet, buffer chain freed + * + */ +int +ipatm_ipinput(inp, m) + struct ip_nif *inp; + KBuffer *m; +{ + int s, space; + +#ifdef DIAGNOSTIC + if (ipatm_print) { + atm_pdu_print(m, "ipatm_ipinput"); + } +#endif + +#if defined(BSD) +#if BSD >= 199103 + +#ifdef DIAGNOSTIC + if (!KB_ISPKT(m)) { + panic("ipatm_ipinput: no packet header"); + } + { + int cnt = 0; + KBuffer *m0 = m; + + while (m0) { + cnt += KB_LEN(m0); + m0 = KB_NEXT(m0); + } + if (m->m_pkthdr.len != cnt) { + panic("ipatm_ipinput: packet length incorrect"); + } + } +#endif + /* + * Save the input ifnet pointer in the packet header + */ + m->m_pkthdr.rcvif = (struct ifnet *)inp->inf_nif; + +#else /* ! BSD >= 199103 */ + /* + * Stick ifnet pointer onto front of packet - hopefully + * there'll be room in the first buffer. + */ + KB_HEADROOM(m, space); + if (space < sizeof(struct ifnet *)) { + KBuffer *n; + + /* + * We have to allocate another buffer and tack it + * onto the front of the packet + */ + KB_ALLOCPKT(n, sizeof(struct ifnet *), + KB_F_NOWAIT, KB_T_HEADER); + if (n == 0) { + KB_FREEALL(m); + ipatm_stat.ias_rcvnobuf++; + return (1); + } + KB_LEN(n) = sizeof(struct ifnet *); + KB_LINKHEAD(n, m); + m = n; + } else { + /* + * Header fits, just adjust buffer controls + */ + KB_HEADADJ(m, sizeof(struct ifnet *)); + } + { + struct ifnet **p; + + KB_DATASTART(m, p, struct ifnet **); + *p = (struct ifnet *)inp->inf_nif; + } +#endif /* ! BSD >= 199103 */ + + /* + * Finally, hand packet off to IP. + * + * NB: Since we're already in the softint kernel state, we + * just call IP directly to avoid the extra unnecessary + * kernel scheduling. + */ + s = splimp(); + if (IF_QFULL(&ipintrq)) { + IF_DROP(&ipintrq); + (void) splx(s); + KB_FREEALL(m); + return (1); + } + + IF_ENQUEUE(&ipintrq, m); + (void) splx(s); +#if BSD < 199506 + ipintr(); +#else + schednetisr ( NETISR_IP ); +#endif /* BSD >= 199506 */ +#endif /* defined(BSD) */ + + return (0); +} + diff --git a/sys/netatm/ipatm/ipatm_load.c b/sys/netatm/ipatm/ipatm_load.c new file mode 100644 index 0000000..8caa635 --- /dev/null +++ b/sys/netatm/ipatm/ipatm_load.c @@ -0,0 +1,878 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: ipatm_load.c,v 1.12 1998/07/30 22:23:00 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * Support for running as a loadable kernel module + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: ipatm_load.c,v 1.12 1998/07/30 22:23:00 mks Exp $"; +#endif + +#ifndef ATM_IP_MODULE +#include "opt_atm.h" +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm.h> +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> + + +/* + * Global variables + */ +int ipatm_vccnt = 0; +int ipatm_vcidle = IPATM_VCIDLE; +int ipatm_print = 0; +u_long last_map_ipdst = 0; +struct ipvcc* last_map_ipvcc = NULL; + +struct ip_nif *ipatm_nif_head = NULL; + +struct ipatm_stat ipatm_stat = {0}; + +struct atm_time ipatm_itimer = {0, 0}; /* VCC idle timer */ + +Atm_endpoint ipatm_endpt = { + NULL, + ENDPT_IP, + ipatm_ioctl, + ipatm_getname, + ipatm_connected, + ipatm_cleared, + ipatm_incoming, + NULL, + NULL, + NULL, + ipatm_cpcs_data, + NULL, + NULL, + NULL, + NULL +}; + +struct sp_info ipatm_vcpool = { + "ipatm vcc pool", /* si_name */ + sizeof(struct ipvcc), /* si_blksiz */ + 10, /* si_blkcnt */ + 100 /* si_maxallow */ +}; + +struct sp_info ipatm_nifpool = { + "ipatm nif pool", /* si_name */ + sizeof(struct ip_nif), /* si_blksiz */ + 5, /* si_blkcnt */ + 20 /* si_maxallow */ +}; + + +/* + * Local functions + */ +static int ipatm_start __P((void)); +static int ipatm_stop __P((void)); + + +/* + * Local variables + */ +static struct atm_ncm ipatm_ncm = { + NULL, + AF_INET, + ipatm_ifoutput, + ipatm_nifstat +}; + +static struct ipatm_listener { + Atm_attributes attr; + Atm_connection *conn; +} ipatm_listeners[] = { +{ + { NULL, /* nif */ + CMAPI_CPCS, /* api */ + 0, /* api_init */ + 0, /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, + ATM_AAL5 + }, + { /* traffic */ + T_ATM_PRESENT, + { + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + T_YES + }, + }, + { /* bearer */ + T_ATM_ANY + }, + { /* bhli */ + T_ATM_ABSENT + }, + { /* blli */ + T_ATM_PRESENT, + T_ATM_ABSENT, + { + { + T_ATM_SIMPLE_ID, + }, + { + T_ATM_ABSENT + } + } + }, + { /* llc */ + T_ATM_PRESENT, + { + T_ATM_LLC_SHARING, + IPATM_LLC_LEN, + IPATM_LLC_HDR + } + }, + { /* called */ + T_ATM_ANY + }, + { /* calling */ + T_ATM_ANY + }, + { /* qos */ + T_ATM_PRESENT, + { + T_ATM_NETWORK_CODING, + { + T_ATM_QOS_CLASS_0, + }, + { + T_ATM_QOS_CLASS_0 + } + } + }, + { /* transit */ + T_ATM_ANY + }, + { /* cause */ + T_ATM_ABSENT + }, + }, + NULL +}, +{ + { NULL, /* nif */ + CMAPI_CPCS, /* api */ + 0, /* api_init */ + 0, /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, + ATM_AAL5 + }, + { /* traffic */ + T_ATM_PRESENT, + { + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + T_YES + }, + }, + { /* bearer */ + T_ATM_ANY + }, + { /* bhli */ + T_ATM_ABSENT + }, + { /* blli */ + T_ATM_ABSENT, + T_ATM_ABSENT + }, + { /* llc */ + T_ATM_ABSENT + }, + { /* called */ + T_ATM_ANY + }, + { /* calling */ + T_ATM_ANY + }, + { /* qos */ + T_ATM_PRESENT, + { + T_ATM_NETWORK_CODING, + { + T_ATM_QOS_CLASS_0, + }, + { + T_ATM_QOS_CLASS_0 + } + } + }, + { /* transit */ + T_ATM_ANY + }, + { /* cause */ + T_ATM_ABSENT + }, + }, + NULL +}, +{ + { NULL, /* nif */ + CMAPI_CPCS, /* api */ + 0, /* api_init */ + 0, /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, + ATM_AAL3_4 + }, + { /* traffic */ + T_ATM_PRESENT, + { + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + T_YES + }, + }, + { /* bearer */ + T_ATM_ANY + }, + { /* bhli */ + T_ATM_ABSENT + }, + { /* blli */ + T_ATM_ABSENT, + T_ATM_ABSENT + }, + { /* llc */ + T_ATM_ABSENT + }, + { /* called */ + T_ATM_ANY + }, + { /* calling */ + T_ATM_ANY + }, + { /* qos */ + T_ATM_PRESENT, + { + T_ATM_NETWORK_CODING, + { + T_ATM_QOS_CLASS_0, + }, + { + T_ATM_QOS_CLASS_0 + } + } + }, + { /* transit */ + T_ATM_ANY + }, + { /* cause */ + T_ATM_ABSENT + }, + }, + NULL +}, +}; + +static struct t_atm_cause ipatm_cause = { + T_ATM_ITU_CODING, + T_ATM_LOC_USER, + T_ATM_CAUSE_UNSPECIFIED_NORMAL, + {0, 0, 0, 0} +}; + + +/* + * Initialize ipatm processing + * + * This will be called during module loading. We'll just register + * ourselves and wait for the packets to start flying. + * + * Arguments: + * none + * + * Returns: + * 0 startup was successful + * errno startup failed - reason indicated + * + */ +static int +ipatm_start() +{ + struct atm_pif *pip; + struct atm_nif *nip; + int err, s, i; + + /* + * Verify software version + */ + if (atm_version != ATM_VERSION) { + log(LOG_ERR, "version mismatch: ipatm=%d.%d kernel=%d.%d\n", + ATM_VERS_MAJ(ATM_VERSION), ATM_VERS_MIN(ATM_VERSION), + ATM_VERS_MAJ(atm_version), ATM_VERS_MIN(atm_version)); + return (EINVAL); + } + + /* + * Register ourselves as a network convergence module + */ + err = atm_netconv_register(&ipatm_ncm); + if (err) + goto done; + + /* + * Register ourselves as an ATM endpoint + */ + err = atm_endpoint_register(&ipatm_endpt); + if (err) + goto done; + + /* + * Get current system configuration + */ + s = splnet(); + for (pip = atm_interface_head; pip; pip = pip->pif_next) { + /* + * Process each network interface + */ + for (nip = pip->pif_nif; nip; nip = nip->nif_pnext) { + struct ifnet *ifp = (struct ifnet *)nip; + struct in_ifaddr *ia; + + /* + * Attach interface + */ + err = ipatm_nifstat(NCM_ATTACH, nip, 0); + if (err) { + (void) splx(s); + goto done; + } + + /* + * If IP address has been set, register it + */ + TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { + if (ia->ia_ifp == ifp) + break; + } + if (ia) { + err = ipatm_nifstat(NCM_SETADDR, nip, (int)ia); + if (err) { + (void) splx(s); + goto done; + } + } + } + } + (void) splx(s); + + /* + * Fill in union fields + */ + ipatm_aal5llc.aal.v.aal5.forward_max_SDU_size = + ATM_NIF_MTU + IPATM_LLC_LEN; + ipatm_aal5llc.aal.v.aal5.backward_max_SDU_size = + ATM_NIF_MTU + IPATM_LLC_LEN; + ipatm_aal5llc.aal.v.aal5.SSCS_type = T_ATM_NULL; + ipatm_aal5llc.blli.v.layer_2_protocol.ID.simple_ID = T_ATM_BLLI2_I8802; + + ipatm_aal5null.aal.v.aal5.forward_max_SDU_size = ATM_NIF_MTU; + ipatm_aal5null.aal.v.aal5.backward_max_SDU_size = ATM_NIF_MTU; + ipatm_aal5null.aal.v.aal5.SSCS_type = T_ATM_NULL; + + ipatm_aal4null.aal.v.aal4.forward_max_SDU_size = ATM_NIF_MTU; + ipatm_aal4null.aal.v.aal4.backward_max_SDU_size = ATM_NIF_MTU; + ipatm_aal4null.aal.v.aal4.SSCS_type = T_ATM_NULL; + ipatm_aal4null.aal.v.aal4.mid_low = 0; + ipatm_aal4null.aal.v.aal4.mid_high = 1023; + + /* + * Listen for incoming calls + */ + for (i = 0; + i < (sizeof(ipatm_listeners) / sizeof(struct ipatm_listener)); + i++) { + struct attr_aal *aalp = &ipatm_listeners[i].attr.aal; + int maxsdu = ATM_NIF_MTU; + + /* + * Fill in union fields + */ + if (ipatm_listeners[i].attr.blli.tag_l2 == T_ATM_PRESENT) { + struct t_atm_blli *bp = &ipatm_listeners[i].attr.blli.v; + + bp->layer_2_protocol.ID.simple_ID = T_ATM_BLLI2_I8802; + maxsdu += IPATM_LLC_LEN; + } + if (aalp->type == ATM_AAL5) { + aalp->v.aal5.forward_max_SDU_size = maxsdu; + aalp->v.aal5.backward_max_SDU_size = maxsdu; + aalp->v.aal5.SSCS_type = T_ATM_NULL; + } else { + aalp->v.aal4.forward_max_SDU_size = maxsdu; + aalp->v.aal4.backward_max_SDU_size = maxsdu; + aalp->v.aal4.SSCS_type = T_ATM_NULL; + aalp->v.aal4.mid_low = 0; + aalp->v.aal4.mid_high = 1023; + } + + /* + * Now start listening + */ + if (err = atm_cm_listen(&ipatm_endpt, (void *)i, + &ipatm_listeners[i].attr, + &ipatm_listeners[i].conn)) + goto done; + } + + /* + * Start background VCC idle timer + */ + atm_timeout(&ipatm_itimer, IPATM_IDLE_TIME, ipatm_itimeout); + +done: + return (err); +} + + +/* + * Halt ipatm processing + * + * This will be called just prior to unloading the module from + * memory. All IP VCCs must be terminated before the protocol can + * be shutdown. + * + * Arguments: + * none + * + * Returns: + * 0 shutdown was successful + * errno shutdown failed - reason indicated + * + */ +static int +ipatm_stop() +{ + struct ip_nif *inp; + int err = 0, i; + int s = splnet(); + + /* + * Any VCCs still open?? + */ + if (ipatm_vccnt) { + + /* Yes, can't stop now */ + err = EBUSY; + goto done; + } + + /* + * Kill VCC idle timer + */ + (void) atm_untimeout(&ipatm_itimer); + + /* + * Stop listening for incoming calls + */ + for (i = 0; + i < (sizeof(ipatm_listeners) / sizeof(struct ipatm_listener)); + i++) { + if (ipatm_listeners[i].conn != NULL) { + (void) atm_cm_release(ipatm_listeners[i].conn, + &ipatm_cause); + } + } + + /* + * Detach all our interfaces + */ + while (inp = ipatm_nif_head) { + (void) ipatm_nifstat(NCM_DETACH, inp->inf_nif, 0); + } + + /* + * De-register from system + */ + (void) atm_netconv_deregister(&ipatm_ncm); + (void) atm_endpoint_deregister(&ipatm_endpt); + + /* + * Free up our storage pools + */ + atm_release_pool(&ipatm_vcpool); + atm_release_pool(&ipatm_nifpool); + +done: + (void) splx(s); + return (err); +} + + +#ifdef ATM_IP_MODULE +/* + ******************************************************************* + * + * Loadable Module Support + * + ******************************************************************* + */ +static int ipatm_doload __P((void)); +static int ipatm_dounload __P((void)); + +/* + * Generic module load processing + * + * This function is called by an OS-specific function when this + * module is being loaded. + * + * Arguments: + * none + * + * Returns: + * 0 load was successful + * errno load failed - reason indicated + * + */ +static int +ipatm_doload() +{ + int err = 0; + + /* + * Start us up + */ + err = ipatm_start(); + if (err) + /* Problems, clean up */ + (void)ipatm_stop(); + + return (err); +} + + +/* + * Generic module unload processing + * + * This function is called by an OS-specific function when this + * module is being unloaded. + * + * Arguments: + * none + * + * Returns: + * 0 unload was successful + * errno unload failed - reason indicated + * + */ +static int +ipatm_dounload() +{ + int err = 0; + + /* + * OK, try to clean up our mess + */ + err = ipatm_stop(); + + return (err); +} + + +#ifdef sun +/* + * Loadable driver description + */ +struct vdldrv ipatm_drv = { + VDMAGIC_PSEUDO, /* Pseudo Driver */ + "ipatm_mod", /* name */ + NULL, /* dev_ops */ + NULL, /* bdevsw */ + NULL, /* cdevsw */ + 0, /* blockmajor */ + 0 /* charmajor */ +}; + + +/* + * Loadable module support entry point + * + * This is the routine called by the vd driver for all loadable module + * functions for this pseudo driver. This routine name must be specified + * on the modload(1) command. This routine will be called whenever the + * modload(1), modunload(1) or modstat(1) commands are issued for this + * module. + * + * Arguments: + * cmd vd command code + * vdp pointer to vd driver's structure + * vdi pointer to command-specific vdioctl_* structure + * vds pointer to status structure (VDSTAT only) + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +int +ipatm_mod(cmd, vdp, vdi, vds) + int cmd; + struct vddrv *vdp; + caddr_t vdi; + struct vdstat *vds; +{ + int err = 0; + + switch (cmd) { + + case VDLOAD: + /* + * Module Load + * + * We dont support any user configuration + */ + err = ipatm_doload(); + if (err == 0) + /* Let vd driver know about us */ + vdp->vdd_vdtab = (struct vdlinkage *)&ipatm_drv; + break; + + case VDUNLOAD: + /* + * Module Unload + */ + err = ipatm_dounload(); + break; + + case VDSTAT: + /* + * Module Status + */ + + /* Not much to say at the moment */ + + break; + + default: + log(LOG_ERR, "ipatm_mod: Unknown vd command 0x%x\n", cmd); + err = EINVAL; + } + + return (err); +} +#endif /* sun */ + +#ifdef __FreeBSD__ + +#include <sys/exec.h> +#include <sys/sysent.h> +#include <sys/lkm.h> + +/* + * Loadable miscellaneous module description + */ +MOD_MISC(ipatm); + + +/* + * Loadable module support "load" entry point + * + * This is the routine called by the lkm driver whenever the + * modload(1) command is issued for this module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +static int +ipatm_load(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + return(ipatm_doload()); +} + + +/* + * Loadable module support "unload" entry point + * + * This is the routine called by the lkm driver whenever the + * modunload(1) command is issued for this module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +static int +ipatm_unload(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + return(ipatm_dounload()); +} + + +/* + * Loadable module support entry point + * + * This is the routine called by the lkm driver for all loadable module + * functions for this driver. This routine name must be specified + * on the modload(1) command. This routine will be called whenever the + * modload(1), modunload(1) or modstat(1) commands are issued for this + * module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * ver lkm version + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +int +ipatm_mod(lkmtp, cmd, ver) + struct lkm_table *lkmtp; + int cmd; + int ver; +{ + MOD_DISPATCH(ipatm, lkmtp, cmd, ver, + ipatm_load, ipatm_unload, lkm_nullcmd); +} +#endif /* __FreeBSD__ */ + +#else /* !ATM_IP_MODULE */ + +/* + ******************************************************************* + * + * Kernel Compiled Module Support + * + ******************************************************************* + */ +static void ipatm_doload __P((void *)); + +SYSINIT(atmipatm, SI_SUB_PROTO_END, SI_ORDER_ANY, ipatm_doload, NULL) + +/* + * Kernel initialization + * + * Arguments: + * arg Not used + * + * Returns: + * none + * + */ +static void +ipatm_doload(void *arg) +{ + int err = 0; + + /* + * Start us up + */ + err = ipatm_start(); + if (err) { + /* Problems, clean up */ + (void)ipatm_stop(); + + log(LOG_ERR, "IP over ATM unable to initialize (%d)!!\n", err); + } + return; +} +#endif /* ATM_IP_MODULE */ + diff --git a/sys/netatm/ipatm/ipatm_output.c b/sys/netatm/ipatm/ipatm_output.c new file mode 100644 index 0000000..7f02f28 --- /dev/null +++ b/sys/netatm/ipatm/ipatm_output.c @@ -0,0 +1,216 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: ipatm_output.c,v 1.6 1998/02/19 20:14:17 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * Output IP packets across an ATM VCC + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: ipatm_output.c,v 1.6 1998/02/19 20:14:17 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm.h> +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> + + +/* + * Output an IP Packet + * + * All IP packets output to an ATM interface will be directed here via + * the atm_ifoutput() function. If there is an ATM VCC already setup for + * the destination IP address, then we'll just send the packet to that VCC. + * Otherwise we will have to setup a new VCC, ARPing for the corresponding + * destination ATM hardware address along the way. + * + * Arguments: + * ifp pointer to ifnet structure + * m pointer to packet buffer chain to be output + * dst pointer to packet's IP destination address + * + * Returns: + * 0 packet "output" was successful + * errno output failed - reason indicated + * + */ +int +ipatm_ifoutput(ifp, m, dst) + struct ifnet *ifp; + KBuffer *m; + struct sockaddr *dst; +{ + struct ipvcc *ivp; + int err = 0; + +#ifdef DIAGNOSTIC + if (ipatm_print) { + atm_pdu_print(m, "ipatm_ifoutput"); + } +#endif + + /* + * See if we've already got an appropriate VCC + */ + ivp = ipatm_iptovc((struct sockaddr_in *)dst, (struct atm_nif *)ifp); + if (ivp) { + + /* + * Reset idle timer + */ + ivp->iv_idle = 0; + + /* + * Can we use this VCC now?? + */ + if ((ivp->iv_state == IPVCC_ACTIVE) && + (ivp->iv_flags & IVF_MAPOK)) { + + /* + * OK, now send packet + */ + err = atm_cm_cpcs_data(ivp->iv_conn, m); + if (err) { + /* + * Output problem, drop packet + */ + KB_FREEALL(m); + } + } else { + + /* + * VCC is unavailable for data packets. Queue packet + * for now, but only maintain a queue length of one. + */ + if (ivp->iv_queue) + KB_FREEALL(ivp->iv_queue); + + ivp->iv_queue = m; + } + } else { + struct in_ifaddr *ia; +#if (defined(BSD) && (BSD < 199306)) + extern struct ifnet loif; +#endif + + /* + * No VCC to destination + */ + + /* + * Is packet for our interface address? + */ + TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) { + if (ia->ia_ifp != ifp) + continue; + if (((struct sockaddr_in *)dst)->sin_addr.s_addr == + IA_SIN(ia)->sin_addr.s_addr) { + + /* + * It's for us - hand packet to loopback driver + */ + (void) if_simloop(ifp, m, dst, 0); + goto done; + } + } + + /* + * Is this a broadcast packet ?? + */ +#if (defined(BSD) && (BSD >= 199306)) + if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr, ifp)) { +#else + if (in_broadcast(((struct sockaddr_in *)dst)->sin_addr)) { +#endif + struct ip_nif *inp; + int s; + + /* + * If interface server exists and provides broadcast + * services, then let it deal with this packet + */ + s = splnet(); + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (inp->inf_nif == (struct atm_nif *)ifp) + break; + } + (void) splx(s); + + if ((inp == NULL) || + (inp->inf_serv == NULL) || + (inp->inf_serv->is_bcast_output == NULL)) { + KB_FREEALL(m); + err = EADDRNOTAVAIL; + goto done; + } + + err = (*inp->inf_serv->is_bcast_output)(inp, m); + goto done; + } + + /* + * How about a multicast packet ?? + */ + if (IN_MULTICAST(ntohl(SATOSIN(dst)->sin_addr.s_addr))) { + /* + * Multicast isn't currently supported + */ + KB_FREEALL(m); + err = EADDRNOTAVAIL; + goto done; + } + + /* + * Well, I guess we need to create an SVC to the destination + */ + if ((err = ipatm_createsvc(ifp, AF_INET, + (caddr_t)&((struct sockaddr_in *)dst)->sin_addr, + &ivp)) == 0) { + /* + * SVC open is proceeding, queue packet + */ + ivp->iv_queue = m; + + } else { + /* + * SVC open failed, release buffers and return + */ + KB_FREEALL(m); + } + } + +done: + return (err); +} + diff --git a/sys/netatm/ipatm/ipatm_serv.h b/sys/netatm/ipatm/ipatm_serv.h new file mode 100644 index 0000000..2046213 --- /dev/null +++ b/sys/netatm/ipatm/ipatm_serv.h @@ -0,0 +1,114 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: ipatm_serv.h,v 1.6 1998/02/19 20:14:21 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * IP/ATM service interface definitions + * + */ + +#ifndef _IPATM_IPATM_SERV_H +#define _IPATM_IPATM_SERV_H + + +/* + * Structures specifying VCC parameters and pointers to all of the IP + * services offered by an external IP interface service provider. + */ +struct ip_vccparm { + Aal_t ivc_aal; /* AAL type */ + Encaps_t ivc_encaps; /* VCC encapsulation */ +}; + +#define IPATM_VCCPARMS 4 /* Number of parameter lists */ + +struct ip_serv { +/* Interfaces to IP/ATM interface services */ + int (*is_ifact) /* Interface activation */ + __P((struct ip_nif *)); + int (*is_ifdact) /* Interface deactivation */ + __P((struct ip_nif *)); + int (*is_ioctl) /* Interface ioctl */ + __P((int, caddr_t, caddr_t)); + +/* Interfaces to IP/ATM ARP services */ + int (*is_arp_pvcopen) /* IP creating dynamic PVC */ + __P((struct ipvcc *)); + int (*is_arp_svcout) /* IP creating outgoing SVC */ + __P((struct ipvcc *, struct in_addr *)); + int (*is_arp_svcin) /* IP creating incoming SVC */ + __P((struct ipvcc *, Atm_addr *, Atm_addr *)); + int (*is_arp_svcact) /* IP SVC is active */ + __P((struct ipvcc *)); + void (*is_arp_close) /* IP closing VCC */ + __P((struct ipvcc *)); + +/* Interfaces to IP/ATM broadcast services */ + int (*is_bcast_output) /* IP broadcast packet output */ + __P((struct ip_nif *, KBuffer *)); + +/* Interfaces to IP/ATM multicast services */ + +/* Ordered list of parameters to try for IP/ATM VCC connections */ + struct ip_vccparm is_vccparm[IPATM_VCCPARMS]; /* List of vcc params */ +}; + + +/* + * ARP Interface + * ---------------- + */ + +/* + * Common header for IP/ATM ARP mappings. For each IP VCC created, the + * appropriate IP/ATM ARP server must assign one of these structures to + * indicate the address mapping. This is the only IP-visible ARP structure. + * The servers may embed this structure at the beginning of their + * module-specific mappings. + */ +struct arpmap { + struct in_addr am_dstip; /* Destination IP address */ + Atm_addr am_dstatm; /* Destination ATM address */ + Atm_addr am_dstatmsub; /* Destination ATM subaddress */ +}; + + +/* + * is_arp_[ps]open() return codes and ipatm_arpnotify() event types + */ +#define MAP_PROCEEDING 1 /* Lookup is proceeding (open only) */ +#define MAP_VALID 2 /* Mapping is valid */ +#define MAP_INVALID 3 /* Mapping is invalid */ +#define MAP_CHANGED 4 /* Mapping has changed */ +#define MAP_FAILED 5 /* Mapping request has failed */ + + +#endif /* _IPATM_IPATM_SERV_H */ diff --git a/sys/netatm/ipatm/ipatm_usrreq.c b/sys/netatm/ipatm/ipatm_usrreq.c new file mode 100644 index 0000000..1f1751c --- /dev/null +++ b/sys/netatm/ipatm/ipatm_usrreq.c @@ -0,0 +1,394 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: ipatm_usrreq.c,v 1.6 1998/05/18 19:14:04 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * Process user requests + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: ipatm_usrreq.c,v 1.6 1998/05/18 19:14:04 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm.h> +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> + + +/* + * Process IP PF_ATM ioctls + * + * Called at splnet. + * + * Arguments: + * code PF_ATM sub-operation code + * data pointer to code specific parameter data area + * arg1 pointer to code specific argument + * + * Returns: + * 0 request procesed + * errno error processing request - reason indicated + * + */ +int +ipatm_ioctl(code, data, arg1) + int code; + caddr_t data; + caddr_t arg1; +{ + struct atmaddreq *aap; + struct atmdelreq *adp; + struct atminfreq *aip; + struct air_ip_vcc_rsp aivr; + struct atm_nif *nip; + struct ip_nif *inp; + struct ipvcc *ivp; + struct vccb *vcp; + struct ipatmpvc pv; + caddr_t cp; + struct in_addr ip; + int space, err = 0; + + + switch (code) { + + case AIOCS_ADD_PVC: + /* + * Add an IP PVC + */ + aap = (struct atmaddreq *)data; + + /* + * Find the IP network interface + */ + if ((nip = atm_nifname(aap->aar_pvc_intf)) == NULL) { + err = ENXIO; + break; + } + + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (inp->inf_nif == nip) + break; + } + if (inp == NULL) { + err = ENXIO; + break; + } + + /* + * Validate PVC params + */ + if (aap->aar_pvc_aal == ATM_AAL5) { + if ((aap->aar_pvc_encaps != ATM_ENC_LLC) && + (aap->aar_pvc_encaps != ATM_ENC_NULL)) { + err = EINVAL; + break; + } + } else if (aap->aar_pvc_aal == ATM_AAL3_4) { + if (aap->aar_pvc_encaps != ATM_ENC_NULL) { + err = EINVAL; + break; + } + } else { + err = EINVAL; + break; + } + + if (aap->aar_pvc_flags & PVC_DYN) { + /* + * For dynamic PVC destination addressing, the + * network interface must have support for this + */ + if ((inp->inf_serv == NULL) || + (inp->inf_serv->is_arp_pvcopen == NULL)) { + err = EDESTADDRREQ; + break; + } + } else { + u_long dst = ((struct sockaddr_in *)&aap->aar_pvc_dst) + ->sin_addr.s_addr; + + if (dst == INADDR_ANY) { + err = EINVAL; + break; + } + } + + /* + * Build connection request + */ + pv.ipp_ipnif = inp; + pv.ipp_vpi = aap->aar_pvc_vpi; + pv.ipp_vci = aap->aar_pvc_vci; + pv.ipp_encaps = aap->aar_pvc_encaps; + pv.ipp_aal = aap->aar_pvc_aal; + if (aap->aar_pvc_flags & PVC_DYN) { + pv.ipp_dst.sin_addr.s_addr = INADDR_ANY; + } else + pv.ipp_dst = *(struct sockaddr_in *)&aap->aar_pvc_dst; + + /* + * Open a new VCC + */ + err = ipatm_openpvc(&pv, &ivp); + break; + + case AIOCS_ADD_ARP: + /* + * Add an ARP mapping + */ + aap = (struct atmaddreq *)data; + + /* + * Validate IP address + */ + if (aap->aar_arp_dst.sa_family != AF_INET) { + err = EAFNOSUPPORT; + break; + } + ip = SATOSIN(&aap->aar_arp_dst)->sin_addr; + + if (aap->aar_arp_intf[0] == '\0') { + /* + * Find the IP network interface associated with + * the supplied IP address + */ + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (ipatm_chknif(ip, inp) == 0) + break; + } + if (inp == NULL) { + err = EADDRNOTAVAIL; + break; + } + } else { + /* + * Find the specified IP network interface + */ + if ((nip = atm_nifname(aap->aar_arp_intf)) == NULL) { + err = ENXIO; + break; + } + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (inp->inf_nif == nip) + break; + } + if (inp == NULL) { + err = ENXIO; + break; + } + } + + if ((ip.s_addr == INADDR_ANY) || +#if (defined(BSD) && (BSD >= 199306)) + in_broadcast(ip, &inp->inf_nif->nif_if) || +#else + in_broadcast(ip) || +#endif + IN_MULTICAST(ntohl(ip.s_addr))) { + err = EADDRNOTAVAIL; + break; + } + + /* + * Notify the responsible ARP service + */ + err = (*inp->inf_serv->is_ioctl)(code, data, inp->inf_isintf); + break; + + case AIOCS_DEL_ARP: + /* + * Delete an ARP mapping + */ + adp = (struct atmdelreq *)data; + + /* + * Validate IP address + */ + if (adp->adr_arp_dst.sa_family != AF_INET) { + err = EAFNOSUPPORT; + break; + } + ip = SATOSIN(&adp->adr_arp_dst)->sin_addr; + + if (adp->adr_arp_intf[0] == '\0') { + /* + * Find the IP network interface associated with + * the supplied IP address + */ + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (ipatm_chknif(ip, inp) == 0) + break; + } + if (inp == NULL) { + err = EADDRNOTAVAIL; + break; + } + } else { + /* + * Find the specified IP network interface + */ + if ((nip = atm_nifname(adp->adr_arp_intf)) == NULL) { + err = ENXIO; + break; + } + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (inp->inf_nif == nip) + break; + } + if (inp == NULL) { + err = ENXIO; + break; + } + } + + if ((ip.s_addr == INADDR_ANY) || +#if (defined(BSD) && (BSD >= 199306)) + in_broadcast(ip, &inp->inf_nif->nif_if) || +#else + in_broadcast(ip) || +#endif + IN_MULTICAST(ntohl(ip.s_addr))) { + err = EADDRNOTAVAIL; + break; + } + + /* + * Notify the responsible ARP service + */ + err = (*inp->inf_serv->is_ioctl)(code, data, inp->inf_isintf); + break; + + case AIOCS_INF_IPM: + /* + * Get IP VCC information + */ + aip = (struct atminfreq *)data; + + if (aip->air_ip_addr.sa_family != AF_INET) + break; + ip = SATOSIN(&aip->air_ip_addr)->sin_addr; + + cp = aip->air_buf_addr; + space = aip->air_buf_len; + + /* + * Loop through all our interfaces + */ + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + /* + * Check out each VCC + */ + for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp; + ivp = Q_NEXT(ivp, struct ipvcc, iv_elem)) { + + if ((ip.s_addr != INADDR_ANY) && + (ip.s_addr != ivp->iv_dst.s_addr)) + continue; + + /* + * Make sure there's room in user buffer + */ + if (space < sizeof(aivr)) { + err = ENOSPC; + break; + } + + /* + * Fill in info to be returned + */ + KM_ZERO((caddr_t)&aivr, sizeof(aivr)); + SATOSIN(&aivr.aip_dst_addr)->sin_family = + AF_INET; + SATOSIN(&aivr.aip_dst_addr)->sin_addr.s_addr = + ivp->iv_dst.s_addr; + (void) sprintf(aivr.aip_intf, "%s%d", + inp->inf_nif->nif_if.if_name, + inp->inf_nif->nif_if.if_unit); + if ((ivp->iv_conn) && + (ivp->iv_conn->co_connvc) && + (vcp = ivp->iv_conn->co_connvc->cvc_vcc)) { + aivr.aip_vpi = vcp->vc_vpi; + aivr.aip_vci = vcp->vc_vci; + aivr.aip_sig_proto = vcp->vc_proto; + } + aivr.aip_flags = ivp->iv_flags; + aivr.aip_state = ivp->iv_state; + + /* + * Copy data to user buffer and + * update buffer controls + */ + err = copyout((caddr_t)&aivr, cp, sizeof(aivr)); + if (err) + break; + cp += sizeof(aivr); + space -= sizeof(aivr); + } + if (err) + break; + } + + /* + * Update buffer pointer/count + */ + aip->air_buf_addr = cp; + aip->air_buf_len = space; + break; + + default: + err = EOPNOTSUPP; + } + + return (err); +} + + +/* + * Get Connection's Application/Owner Name + * + * Arguments: + * tok ipatm connection token (pointer to ipvcc) + * + * Returns: + * addr pointer to string containing our name + * + */ +caddr_t +ipatm_getname(tok) + void *tok; +{ + return ("IP"); +} + diff --git a/sys/netatm/ipatm/ipatm_var.h b/sys/netatm/ipatm/ipatm_var.h new file mode 100644 index 0000000..6048284 --- /dev/null +++ b/sys/netatm/ipatm/ipatm_var.h @@ -0,0 +1,215 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: ipatm_var.h,v 1.8 1998/03/24 20:56:57 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * Protocol control blocks + * + */ + +#ifndef _IPATM_IPATM_VAR_H +#define _IPATM_IPATM_VAR_H + +#ifdef ATM_KERNEL +/* + * Structure containing information for each VCC, both SVC and PVC, which + * supports IP traffic. + */ +struct ipvcc { + Qelem_t iv_elem; /* ip_nif queueing links */ + u_short iv_flags; /* VCC flags (see below) */ + u_char iv_state; /* VCC state (see below) */ + Atm_connection *iv_conn; /* Connection manager token */ + struct in_addr iv_dst; /* Peer's IP address */ + struct ip_nif *iv_ipnif; /* IP network interface */ + struct atm_time iv_time; /* Timer controls */ + short iv_idle; /* VCC idle timer */ + u_char iv_parmx; /* Index into provider's vcc params */ + KBuffer *iv_queue; /* Packet waiting for VCC */ + struct arpmap *iv_arpent; /* ARP entry for VCC */ + struct ipvcc *iv_arpnext; /* ARP link field */ + Atm_connection *iv_arpconn; /* ARP connection manager token */ +}; +#define iv_forw iv_elem.q_forw +#define iv_back iv_elem.q_back +#endif /* ATM_KERNEL */ + +/* + * VCC Flags + */ +#define IVF_PVC 0x0001 /* PVC */ +#define IVF_SVC 0x0002 /* SVC */ +#define IVF_LLC 0x0004 /* VCC uses LLC/SNAP encapsulation */ +#define IVF_MAPOK 0x0008 /* VCC ARP mapping is valid */ +#define IVF_NOIDLE 0x0010 /* Do not idle-timeout this VCC */ + +/* + * VCC States + */ +#define IPVCC_FREE 0 /* No VCC associated with entry */ +#define IPVCC_PMAP 1 /* SVC waiting for ARP mapping */ +#define IPVCC_POPEN 2 /* Pending SVC open completion */ +#define IPVCC_PACCEPT 3 /* Pending SVC accept completion */ +#define IPVCC_ACTPENT 4 /* PVC open - waiting for ARP entry */ +#define IPVCC_ACTIVE 5 /* VCC open - available */ +#define IPVCC_CLOSED 6 /* VCC has been closed */ + + +#ifdef ATM_KERNEL +/* + * Structure containing IP-specific information for each ATM network + * interface in the system. + */ +struct ip_nif { + struct ip_nif *inf_next; /* Next on interface chain */ + struct atm_nif *inf_nif; /* ATM network interface */ + u_short inf_state; /* Interface state (see below) */ + struct in_ifaddr *inf_addr; /* Interface's IP address */ + Queue_t inf_vcq; /* VCC connections queue */ + struct ip_serv *inf_serv; /* Interface service provider */ + +/* For use by IP interface service provider (ie signalling manager) */ + caddr_t inf_isintf; /* Interface control block */ + +/* IP/ATM provided interface services */ + void (*inf_arpnotify)/* ARP event notification */ + __P((struct ipvcc *, int)); + int (*inf_ipinput) /* IP packet input */ + __P((struct ip_nif *, KBuffer *)); + int (*inf_createsvc)/* Create an IP SVC */ + __P((struct ifnet *, u_short, caddr_t, + struct ipvcc **)); +}; + +/* + * Network Interface States + */ +#define IPNIF_ADDR 1 /* Waiting for i/f address */ +#define IPNIF_SIGMGR 2 /* Waiting for sigmgr attach */ +#define IPNIF_ACTIVE 3 /* Active */ + + +/* + * Global IP/ATM Statistics + */ +struct ipatm_stat { + u_long ias_rcvstate; /* Packets received, bad vcc state */ + u_long ias_rcvnobuf; /* Packets received, no buf avail */ +}; + + +/* + * Structure to pass parameters for ipatm_openpvc() + */ +struct ipatmpvc { + struct ip_nif *ipp_ipnif; /* PVC's IP network interface */ + u_short ipp_vpi; /* VPI value */ + u_short ipp_vci; /* VCI value */ + Aal_t ipp_aal; /* AAL type */ + Encaps_t ipp_encaps; /* VCC encapsulation */ + struct sockaddr_in ipp_dst; /* Destination's IP address */ +}; + + +/* + * Timer macros + */ +#define IPVCC_TIMER(s, t) atm_timeout(&(s)->iv_time, (t), ipatm_timeout) +#define IPVCC_CANCEL(s) atm_untimeout(&(s)->iv_time) + +/* + * Misc useful macros + */ +#define SATOSIN(sa) ((struct sockaddr_in *)(sa)) + + +/* + * Global function declarations + */ + /* ipatm_event.c */ +void ipatm_timeout __P((struct atm_time *)); +void ipatm_connected __P((void *)); +void ipatm_cleared __P((void *, struct t_atm_cause *)); +void ipatm_arpnotify __P((struct ipvcc *, int)); +void ipatm_itimeout __P((struct atm_time *)); + + /* ipatm_if.c */ +int ipatm_nifstat __P((int, struct atm_nif *, int)); + + /* ipatm_input.c */ +void ipatm_cpcs_data __P((void *, KBuffer *)); +int ipatm_ipinput __P((struct ip_nif *, KBuffer *)); + + /* ipatm_load.c */ + + /* ipatm_output.c */ +int ipatm_ifoutput __P((struct ifnet *, KBuffer *, + struct sockaddr *)); + + /* ipatm_usrreq.c */ +int ipatm_ioctl __P((int, caddr_t, caddr_t)); +caddr_t ipatm_getname __P((void *)); + + /* ipatm_vcm.c */ +int ipatm_openpvc __P((struct ipatmpvc *, struct ipvcc **)); +int ipatm_createsvc __P((struct ifnet *, u_short, caddr_t, + struct ipvcc **)); +int ipatm_opensvc __P((struct ipvcc *)); +int ipatm_retrysvc __P((struct ipvcc *)); +void ipatm_activate __P((struct ipvcc *)); +int ipatm_incoming __P((void *, Atm_connection *, Atm_attributes *, + void **)); +int ipatm_closevc __P((struct ipvcc *, int)); +int ipatm_chknif __P((struct in_addr, struct ip_nif *)); +struct ipvcc *ipatm_iptovc __P((struct sockaddr_in *, struct atm_nif *)); + + +/* + * External variables + */ +extern int ipatm_vccnt; +extern int ipatm_vcidle; +extern int ipatm_print; +extern u_long last_map_ipdst; +extern struct ipvcc *last_map_ipvcc; +extern struct ip_nif *ipatm_nif_head; +extern struct sp_info ipatm_vcpool; +extern struct sp_info ipatm_nifpool; +extern struct ipatm_stat ipatm_stat; +extern struct atm_time ipatm_itimer; +extern Atm_endpoint ipatm_endpt; +extern Atm_attributes ipatm_aal5llc; +extern Atm_attributes ipatm_aal5null; +extern Atm_attributes ipatm_aal4null; + +#endif /* ATM_KERNEL */ + +#endif /* _IPATM_IPATM_VAR_H */ diff --git a/sys/netatm/ipatm/ipatm_vcm.c b/sys/netatm/ipatm/ipatm_vcm.c new file mode 100644 index 0000000..5d6a7fc --- /dev/null +++ b/sys/netatm/ipatm/ipatm_vcm.c @@ -0,0 +1,1245 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: ipatm_vcm.c,v 1.13 1998/08/06 18:21:14 mks Exp $ + * + */ + +/* + * IP Over ATM Support + * ------------------- + * + * Virtual Channel Manager + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: ipatm_vcm.c,v 1.13 1998/08/06 18:21:14 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm.h> +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> + + +Atm_attributes ipatm_aal5llc = { + NULL, /* nif */ + CMAPI_CPCS, /* api */ + 0, /* api_init */ + 0, /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, + ATM_AAL5 + }, + { /* traffic */ + T_ATM_PRESENT, + { + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + T_YES + }, + }, + { /* bearer */ + T_ATM_PRESENT, + { + T_ATM_CLASS_X, + T_ATM_NULL, + T_ATM_NULL, + T_NO, + T_ATM_1_TO_1 + } + }, + { /* bhli */ + T_ATM_ABSENT + }, + { /* blli */ + T_ATM_PRESENT, + T_ATM_ABSENT, + { + { + T_ATM_SIMPLE_ID, + }, + { + T_ATM_ABSENT + } + } + }, + { /* llc */ + T_ATM_PRESENT, + { + T_ATM_LLC_SHARING, + IPATM_LLC_LEN, + IPATM_LLC_HDR + } + }, + { /* called */ + T_ATM_PRESENT, + }, + { /* calling */ + T_ATM_ABSENT + }, + { /* qos */ + T_ATM_PRESENT, + { + T_ATM_NETWORK_CODING, + { + T_ATM_QOS_CLASS_0, + }, + { + T_ATM_QOS_CLASS_0 + } + } + }, + { /* transit */ + T_ATM_ABSENT + }, + { /* cause */ + T_ATM_ABSENT + } +}; + +Atm_attributes ipatm_aal5null = { + NULL, /* nif */ + CMAPI_CPCS, /* api */ + 0, /* api_init */ + sizeof(struct ifnet *), /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, + ATM_AAL5 + }, + { /* traffic */ + T_ATM_PRESENT, + { + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + T_YES + }, + }, + { /* bearer */ + T_ATM_PRESENT, + { + T_ATM_CLASS_X, + T_ATM_NULL, + T_ATM_NULL, + T_NO, + T_ATM_1_TO_1 + } + }, + { /* bhli */ + T_ATM_ABSENT + }, + { /* blli */ + T_ATM_ABSENT, + T_ATM_ABSENT + }, + { /* llc */ + T_ATM_ABSENT + }, + { /* called */ + T_ATM_PRESENT, + }, + { /* calling */ + T_ATM_ABSENT + }, + { /* qos */ + T_ATM_PRESENT, + { + T_ATM_NETWORK_CODING, + { + T_ATM_QOS_CLASS_0, + }, + { + T_ATM_QOS_CLASS_0 + } + } + }, + { /* transit */ + T_ATM_ABSENT + }, + { /* cause */ + T_ATM_ABSENT + } +}; + +Atm_attributes ipatm_aal4null = { + NULL, /* nif */ + CMAPI_CPCS, /* api */ + 0, /* api_init */ + sizeof(struct ifnet *), /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, + ATM_AAL3_4 + }, + { /* traffic */ + T_ATM_PRESENT, + { + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + T_YES + }, + }, + { /* bearer */ + T_ATM_PRESENT, + { + T_ATM_CLASS_X, + T_ATM_NULL, + T_ATM_NULL, + T_NO, + T_ATM_1_TO_1 + } + }, + { /* bhli */ + T_ATM_ABSENT + }, + { /* blli */ + T_ATM_ABSENT, + T_ATM_ABSENT + }, + { /* llc */ + T_ATM_ABSENT + }, + { /* called */ + T_ATM_PRESENT, + }, + { /* calling */ + T_ATM_ABSENT + }, + { /* qos */ + T_ATM_PRESENT, + { + T_ATM_NETWORK_CODING, + { + T_ATM_QOS_CLASS_0, + }, + { + T_ATM_QOS_CLASS_0 + } + } + }, + { /* transit */ + T_ATM_ABSENT + }, + { /* cause */ + T_ATM_ABSENT + } +}; + +static struct t_atm_cause ipatm_cause = { + T_ATM_ITU_CODING, + T_ATM_LOC_USER, + 0, + {0, 0, 0, 0} +}; + + +/* + * Open an IP PVC + * + * This function will perform all actions necessary to activate a + * PVC for IP usage. In particular, it will allocate control blocks, + * open the PVC, initialize PVC stack, and initiate whatever ARP + * procedures are required. + * + * Arguments: + * pvp pointer to PVC parameter structure + * sivp address to return pointer to IP PVC control block + * + * Returns: + * 0 PVC was successfully opened + * errno open failed - reason indicated + * + */ +int +ipatm_openpvc(pvp, sivp) + struct ipatmpvc *pvp; + struct ipvcc **sivp; +{ + struct ipvcc *ivp; + Atm_attributes *ap; + Atm_addr_pvc *pvcp; + struct atm_nif *nip; + struct ip_nif *inp; + int s, err = 0; + + inp = pvp->ipp_ipnif; + nip = inp->inf_nif; + + /* + * Make sure interface is ready to go + */ + if (inp->inf_state != IPNIF_ACTIVE) { + err = ENETDOWN; + goto done; + } + + /* + * Validate fixed destination IP address + */ + if (pvp->ipp_dst.sin_addr.s_addr != INADDR_ANY) { +#if (defined(BSD) && (BSD >= 199306)) + if (in_broadcast(pvp->ipp_dst.sin_addr, &nip->nif_if) || +#else + if (in_broadcast(pvp->ipp_dst.sin_addr) || +#endif + IN_MULTICAST(ntohl(pvp->ipp_dst.sin_addr.s_addr)) || + ipatm_chknif(pvp->ipp_dst.sin_addr, inp)) { + err = EINVAL; + goto done; + } + } + + /* + * Allocate IP VCC block + */ + ivp = (struct ipvcc *)atm_allocate(&ipatm_vcpool); + if (ivp == NULL) { + err = ENOMEM; + goto done; + } + + /* + * Initialize the PVC + */ + ivp->iv_flags = IVF_PVC; + if (pvp->ipp_encaps == ATM_ENC_LLC) + ivp->iv_flags |= IVF_LLC; + + /* + * Fill out connection attributes + */ + if (pvp->ipp_aal == ATM_AAL5) { + if (pvp->ipp_encaps == ATM_ENC_LLC) + ap = &ipatm_aal5llc; + else + ap = &ipatm_aal5null; + } else { + ap = &ipatm_aal4null; + } + + ap->nif = nip; + ap->traffic.v.forward.PCR_all_traffic = nip->nif_pif->pif_pcr; + ap->traffic.v.backward.PCR_all_traffic = nip->nif_pif->pif_pcr; + ap->called.addr.address_format = T_ATM_PVC_ADDR; + ap->called.addr.address_length = sizeof(Atm_addr_pvc); + pvcp = (Atm_addr_pvc *)ap->called.addr.address; + ATM_PVC_SET_VPI(pvcp, pvp->ipp_vpi); + ATM_PVC_SET_VCI(pvcp, pvp->ipp_vci); + ap->called.subaddr.address_format = T_ATM_ABSENT; + ap->called.subaddr.address_length = 0; + + /* + * Create PVC + */ + err = atm_cm_connect(&ipatm_endpt, ivp, ap, &ivp->iv_conn); + if (err) { + atm_free((caddr_t)ivp); + goto done; + } + + /* + * Save PVC information and link in VCC + */ + /* ivp->iv_ = ap->headout; */ + + /* + * Queue VCC onto its network interface + */ + s = splnet(); + ipatm_vccnt++; + ENQUEUE(ivp, struct ipvcc, iv_elem, inp->inf_vcq); + ivp->iv_ipnif = inp; + (void) splx(s); + + /* + * Set destination IP address and IPVCC state + */ + if (pvp->ipp_dst.sin_addr.s_addr == INADDR_ANY) { + /* + * Initiate ARP processing + */ + switch ((*inp->inf_serv->is_arp_pvcopen)(ivp)) { + + case MAP_PROCEEDING: + /* + * Wait for answer + */ + ivp->iv_state = IPVCC_ACTIVE; + break; + + case MAP_VALID: + /* + * We've got our answer already + */ + ivp->iv_state = IPVCC_ACTIVE; + ivp->iv_flags |= IVF_MAPOK; + ivp->iv_dst.s_addr = ivp->iv_arpent->am_dstip.s_addr; + break; + + case MAP_FAILED: + /* + * Try again later + */ + ivp->iv_state = IPVCC_ACTPENT; + IPVCC_TIMER(ivp, 1 * ATM_HZ); + break; + + default: + panic("ipatm_openpvc: invalid arp_pvcopen return"); + } + + } else { + /* + * Use configured IP destination + */ + ivp->iv_dst.s_addr = pvp->ipp_dst.sin_addr.s_addr; + ivp->iv_state = IPVCC_ACTIVE; + ivp->iv_flags |= IVF_MAPOK; + } + +done: + if (err) + *sivp = NULL; + else + *sivp = ivp; + return (err); +} + + +/* + * Create an IP SVC + * + * This function will initiate the creation of an IP SVC. The IP VCC + * control block will be initialized and, if required, we will initiate + * ARP processing in order to resolve the destination's ATM address. Once + * the destination ATM address is known, ipatm_opensvc() will be called. + * + * Arguments: + * ifp pointer to destination ifnet structure + * daf destination address family type + * dst pointer to destination address + * sivp address to return pointer to IP SVC control block + * + * Returns: + * 0 SVC creation was successfully initiated + * errno creation failed - reason indicated + * + */ +int +ipatm_createsvc(ifp, daf, dst, sivp) + struct ifnet *ifp; + u_short daf; + caddr_t dst; + struct ipvcc **sivp; +{ + struct atm_nif *nip = (struct atm_nif *)ifp; + struct ip_nif *inp; + struct ipvcc *ivp; + struct in_addr *ip; + Atm_addr *atm; + int s, err = 0; + + /* + * Get IP interface and make sure its ready + */ + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (inp->inf_nif == nip) + break; + } + if (inp == NULL) { + err = ENXIO; + goto done; + } + if (inp->inf_state != IPNIF_ACTIVE) { + err = ENETDOWN; + goto done; + } + + /* + * Validate destination address + */ + if (daf == AF_INET) { + /* + * Destination is IP address + */ + ip = (struct in_addr *)dst; + atm = NULL; + if (ip->s_addr == INADDR_ANY) { + err = EADDRNOTAVAIL; + goto done; + } + } else if (daf == AF_ATM) { + /* + * Destination is ATM address + */ + atm = (Atm_addr *)dst; + ip = NULL; + if (atm->address_format == T_ATM_ABSENT) { + err = EINVAL; + goto done; + } + } else { + err = EINVAL; + goto done; + } + + /* + * Make sure we have services provider and ARP support + */ + if ((inp->inf_serv == NULL) || + (inp->inf_serv->is_arp_svcout == NULL)) { + err = ENETDOWN; + goto done; + } + + /* + * Allocate IP VCC + */ + ivp = (struct ipvcc *)atm_allocate(&ipatm_vcpool); + if (ivp == NULL) { + err = ENOMEM; + goto done; + } + + /* + * Initialize SVC + */ + ivp->iv_flags = IVF_SVC; + ivp->iv_ipnif = inp; + + /* + * Get destination ATM address + */ + if (daf == AF_INET) { + /* + * ARP is the way... + */ + ivp->iv_dst.s_addr = ip->s_addr; + + switch ((*inp->inf_serv->is_arp_svcout)(ivp, ip)) { + + case MAP_PROCEEDING: + /* + * Wait for answer + */ + ivp->iv_state = IPVCC_PMAP; + IPVCC_TIMER(ivp, IPATM_ARP_TIME); + break; + + case MAP_VALID: + /* + * We've got our answer already, so open SVC + */ + ivp->iv_flags |= IVF_MAPOK; + err = ipatm_opensvc(ivp); + if (err) { + (*inp->inf_serv->is_arp_close)(ivp); + atm_free((caddr_t)ivp); + goto done; + } + break; + + case MAP_FAILED: + /* + * So sorry...come again + */ + atm_free((caddr_t)ivp); + err = ENETDOWN; + goto done; + + default: + panic("ipatm_createsvc: invalid arp_svcout return"); + } + } else { + /* + * We were given the ATM address, so open the SVC + * + * Create temporary arp map entry so that opensvc() works. + * Caller must set up a permanent entry immediately! (yuk) + */ + struct arpmap map; + + ATM_ADDR_COPY(atm, &map.am_dstatm); + map.am_dstatmsub.address_format = T_ATM_ABSENT; + map.am_dstatmsub.address_length = 0; + ivp->iv_arpent = ↦ + err = ipatm_opensvc(ivp); + if (err) { + atm_free((caddr_t)ivp); + goto done; + } + ivp->iv_arpent = NULL; + } + + /* + * Queue VCC onto its network interface + */ + s = splnet(); + ipatm_vccnt++; + ENQUEUE(ivp, struct ipvcc, iv_elem, inp->inf_vcq); + (void) splx(s); + +done: + if (err) + *sivp = NULL; + else + *sivp = ivp; + return (err); +} + + +/* + * Open an IP SVC + * + * This function will continue the IP SVC creation process. Here, we + * will issue an SVC open to the signalling manager and then wait for + * the final SVC setup results. + * + * Arguments: + * ivp pointer to IP SVC to open + * + * Returns: + * 0 SVC open was successfully initiated + * errno open failed - reason indicated + * + */ +int +ipatm_opensvc(ivp) + struct ipvcc *ivp; +{ + struct ip_nif *inp = ivp->iv_ipnif; + Atm_attributes *ap; + int err = 0, i; + + /* + * Cancel possible arp timeout + */ + IPVCC_CANCEL(ivp); + + /* + * Fill out connection attributes + */ + i = ivp->iv_parmx; + if (inp->inf_serv->is_vccparm[i].ivc_aal == ATM_AAL5) { + if (inp->inf_serv->is_vccparm[i].ivc_encaps == ATM_ENC_LLC) { + ap = &ipatm_aal5llc; + ivp->iv_flags |= IVF_LLC; + } else { + ap = &ipatm_aal5null; + ivp->iv_flags &= ~IVF_LLC; + } + } else { + ap = &ipatm_aal4null; + ivp->iv_flags &= ~IVF_LLC; + } + + ap->nif = inp->inf_nif; + ap->traffic.v.forward.PCR_all_traffic = inp->inf_nif->nif_pif->pif_pcr; + ap->traffic.v.backward.PCR_all_traffic = inp->inf_nif->nif_pif->pif_pcr; + + ATM_ADDR_COPY(&ivp->iv_arpent->am_dstatm, &ap->called.addr); + ATM_ADDR_COPY(&ivp->iv_arpent->am_dstatmsub, &ap->called.subaddr); + + /* + * Initiate SVC open + */ + err = atm_cm_connect(&ipatm_endpt, ivp, ap, &ivp->iv_conn); + switch (err) { + + case EINPROGRESS: + /* + * Call is progressing + */ + /* ivp->iv_ = ap->headout; */ + + /* + * Now we just wait for a CALL_CONNECTED event + */ + ivp->iv_state = IPVCC_POPEN; + IPVCC_TIMER(ivp, IPATM_SVC_TIME); + err = 0; + break; + + case 0: + /* + * We've been hooked up with a shared VCC + */ + /* ivp->iv_ = ap->headout; */ + ipatm_activate(ivp); + break; + } + + return (err); +} + + +/* + * Retry an IP SVC Open + * + * This function will attempt to retry a failed SVC open request. The IP + * interface service provider specifies a list of possible VCC parameters + * for IP to use. We will try each set of parameters in turn until either + * an open succeeds or we reach the end of the list. + * + * Arguments: + * ivp pointer to IP SVC + * + * Returns: + * 0 SVC (re)open was successfully initiated + * else retry failed + * + */ +int +ipatm_retrysvc(ivp) + struct ipvcc *ivp; +{ + struct ip_nif *inp = ivp->iv_ipnif; + + /* + * If there isn't another set of vcc parameters to try, return + */ + if ((++ivp->iv_parmx >= IPATM_VCCPARMS) || + (inp->inf_serv->is_vccparm[ivp->iv_parmx].ivc_aal == 0)) + return (1); + + /* + * Okay, now initiate open with a new set of parameters + */ + return (ipatm_opensvc(ivp)); +} + + +/* + * Finish IP SVC Activation + * + * Arguments: + * ivp pointer to IP SVC + * + * Returns: + * none + * + */ +void +ipatm_activate(ivp) + struct ipvcc *ivp; +{ + + /* + * Connection is now active + */ + ivp->iv_state = IPVCC_ACTIVE; + IPVCC_CANCEL(ivp); + + /* + * Tell ARP module that connection is active + */ + if ((*ivp->iv_ipnif->inf_serv->is_arp_svcact)(ivp)) { + (void) ipatm_closevc(ivp, T_ATM_CAUSE_TEMPORARY_FAILURE); + return; + } + + /* + * Send any queued packet + */ + if ((ivp->iv_flags & IVF_MAPOK) && ivp->iv_queue) { + struct sockaddr_in sin; + struct ifnet *ifp; + + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = ivp->iv_dst.s_addr; + ifp = (struct ifnet *)ivp->iv_ipnif->inf_nif; + (void) ipatm_ifoutput(ifp, ivp->iv_queue, + (struct sockaddr *)&sin); + ivp->iv_queue = NULL; + } +} + + +/* + * Process Incoming Calls + * + * This function will receive control when an incoming call has been matched + * to one of our registered listen parameter blocks. Assuming the call passes + * acceptance criteria and all required resources are available, we will + * create an IP SVC and notify the connection manager of our decision. We + * will then await notification of the final SVC setup results. If any + * problems are encountered, we will just tell the connection manager to + * reject the call. + * + * Called at splnet. + * + * Arguments: + * tok owner's matched listening token + * cop pointer to incoming call's connection block + * ap pointer to incoming call's attributes + * tokp pointer to location to store our connection token + * + * Returns: + * 0 call is accepted + * errno call rejected - reason indicated + * + */ +int +ipatm_incoming(tok, cop, ap, tokp) + void *tok; + Atm_connection *cop; + Atm_attributes *ap; + void **tokp; +{ + struct atm_nif *nip = ap->nif; + struct ip_nif *inp; + struct ipvcc *ivp = NULL; + int err, cause; + int usellc = 0, mtu = ATM_NIF_MTU; + + /* + * Get IP interface and make sure its ready + */ + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (inp->inf_nif == nip) + break; + } + if ((inp == NULL) || (inp->inf_state != IPNIF_ACTIVE)) { + err = ENETUNREACH; + cause = T_ATM_CAUSE_SERVICE_OR_OPTION_UNAVAILABLE; + goto reject; + } + + /* + * Make sure we have services provider and ARP support + */ + if ((inp->inf_serv == NULL) || + (inp->inf_serv->is_arp_svcin == NULL)) { + err = ENETUNREACH; + cause = T_ATM_CAUSE_SERVICE_OR_OPTION_UNAVAILABLE; + goto reject; + } + + /* + * Check for LLC encapsulation + */ + if ((ap->blli.tag_l2 == T_ATM_PRESENT) && + (ap->blli.v.layer_2_protocol.ID_type == T_ATM_SIMPLE_ID) && + (ap->blli.v.layer_2_protocol.ID.simple_ID == T_ATM_BLLI2_I8802)) { + usellc = 1; + mtu += IPATM_LLC_LEN; + } + + /* + * Verify requested MTU + */ + if (ap->aal.type == ATM_AAL5) { + if ((ap->aal.v.aal5.forward_max_SDU_size > mtu) || + (ap->aal.v.aal5.backward_max_SDU_size < mtu)) { + err = ENETUNREACH; + cause = T_ATM_CAUSE_AAL_PARAMETERS_NOT_SUPPORTED; + goto reject; + } + } else { + if ((ap->aal.v.aal4.forward_max_SDU_size > mtu) || + (ap->aal.v.aal4.backward_max_SDU_size < mtu)) { + err = ENETUNREACH; + cause = T_ATM_CAUSE_AAL_PARAMETERS_NOT_SUPPORTED; + goto reject; + } + } + + /* + * Allocate IP VCC + */ + ivp = (struct ipvcc *)atm_allocate(&ipatm_vcpool); + if (ivp == NULL) { + err = ENOMEM; + cause = T_ATM_CAUSE_UNSPECIFIED_RESOURCE_UNAVAILABLE; + goto reject; + } + + /* + * Initialize SVC + */ + ivp->iv_flags = IVF_SVC; + ivp->iv_ipnif = inp; + if (usellc) + ivp->iv_flags |= IVF_LLC; + + /* + * Lookup ARP entry for destination + */ + switch ((*inp->inf_serv->is_arp_svcin) + (ivp, &ap->calling.addr, &ap->calling.subaddr)) { + + case MAP_PROCEEDING: + /* + * We'll be (hopefully) notified later + */ + break; + + case MAP_VALID: + /* + * We've got our answer already + */ + ivp->iv_flags |= IVF_MAPOK; + ivp->iv_dst.s_addr = ivp->iv_arpent->am_dstip.s_addr; + break; + + case MAP_FAILED: + /* + * So sorry...come again + */ + err = ENETUNREACH; + cause = T_ATM_CAUSE_SERVICE_OR_OPTION_UNAVAILABLE; + goto reject; + + default: + panic("ipatm_incoming: invalid arp_svcin return"); + } + + /* + * Accept SVC connection + */ + ivp->iv_state = IPVCC_PACCEPT; + + /* + * Save VCC information + */ + ivp->iv_conn = cop; + *tokp = ivp; + /* ivp->iv_ = ap->headout; */ + + /* + * Queue VCC onto its network interface + */ + ipatm_vccnt++; + ENQUEUE(ivp, struct ipvcc, iv_elem, inp->inf_vcq); + + /* + * Wait for a CALL_CONNECTED event + */ + IPVCC_TIMER(ivp, IPATM_SVC_TIME); + + return (0); + +reject: + /* + * Clean up after call failure + */ + if (ivp) { + (*inp->inf_serv->is_arp_close)(ivp); + atm_free((caddr_t)ivp); + } + ap->cause.tag = T_ATM_PRESENT; + ap->cause.v = ipatm_cause; + ap->cause.v.cause_value = cause; + return (err); +} + + +/* + * Close an IP VCC + * + * This function will close an IP VCC (PVC or SVC), including notifying + * the signalling and ARP subsystems of the VCC's demise and cleaning + * up memory after ourselves. + * + * Arguments: + * ivp pointer to VCC + * code cause code + * + * Returns: + * 0 VCC successfully closed + * errno close failed - reason indicated + * + */ +int +ipatm_closevc(ivp, code) + struct ipvcc *ivp; + int code; +{ + struct ip_nif *inp = ivp->iv_ipnif; + int s, err; + + /* + * Make sure VCC hasn't been through here already + */ + switch (ivp->iv_state) { + + case IPVCC_FREE: + return (EALREADY); + } + + /* + * Reset lookup cache + */ + if (last_map_ipvcc == ivp) { + last_map_ipvcc = NULL; + last_map_ipdst = 0; + } + + /* + * Tell ARP about SVCs and dynamic PVCs + */ + if (inp->inf_serv && + ((ivp->iv_flags & IVF_SVC) || inp->inf_serv->is_arp_pvcopen)) { + (*inp->inf_serv->is_arp_close)(ivp); + } + + /* + * Free queued packets + */ + if (ivp->iv_queue) + KB_FREEALL(ivp->iv_queue); + + /* + * Cancel any timers + */ + IPVCC_CANCEL(ivp); + + /* + * Close VCC + */ + switch (ivp->iv_state) { + + case IPVCC_PMAP: + break; + + case IPVCC_POPEN: + case IPVCC_PACCEPT: + case IPVCC_ACTPENT: + case IPVCC_ACTIVE: + ipatm_cause.cause_value = code; + err = atm_cm_release(ivp->iv_conn, &ipatm_cause); + if (err) { + log(LOG_ERR, + "ipatm_closevc: release fail: err=%d\n", err); + } + break; + + case IPVCC_CLOSED: + break; + + default: + log(LOG_ERR, + "ipatm_closevc: unknown state: ivp=0x%x, state=%d\n", + (int)ivp, ivp->iv_state); + } + + /* + * Remove VCC from network i/f + */ + s = splnet(); + DEQUEUE(ivp, struct ipvcc, iv_elem, inp->inf_vcq); + + /* + * Reset state just to be sure + */ + ivp->iv_state = IPVCC_FREE; + + /* + * If ARP module is done with VCC too, then free it + */ + if (ivp->iv_arpconn == NULL) + atm_free((caddr_t)ivp); + ipatm_vccnt--; + (void) splx(s); + + return (0); +} + + +/* + * Check if IP address is valid on a Network Interface + * + * Checks whether the supplied IP address is allowed to be assigned to + * the supplied IP network interface. + * + * Arguments: + * in IP address + * inp pointer to IP network interface + * + * Returns: + * 0 - OK to assign + * 1 - not valid to assign + * + */ +int +ipatm_chknif(in, inp) + struct in_addr in; + struct ip_nif *inp; +{ + struct in_ifaddr *ia; + u_long i; + + /* + * Make sure there's an interface requested + */ + if (inp == NULL) + return (1); + + /* + * Make sure we have an IP address + */ + i = ntohl(in.s_addr); + if (i == 0) + return (1); + + /* + * Make sure an interface address is set + */ + ia = inp->inf_addr; + if (ia == NULL) + return (1); + + /* + * Make sure we're on the right subnet + */ + if ((i & ia->ia_subnetmask) != ia->ia_subnet) + return (1); + + return (0); +} + + +/* + * Map an IP Address to an IP VCC + * + * Given a destination IP address, this function will return a pointer + * to the appropriate output IP VCC to which to send the packet. + * This is currently implemented using a one-behind cache containing the + * last successful mapping result. If the cache lookup fails, then a + * simple linear search of all IP VCCs on the destination network interface + * is performed. This is obviously an area to look at for performance + * improvements. + * + * Arguments: + * dst pointer to destination IP address + * nip pointer to destination network interface + * + * Returns: + * addr pointer to located IP VCC + * 0 no such mapping exists + * + */ +struct ipvcc * +ipatm_iptovc(dst, nip) + struct sockaddr_in *dst; + struct atm_nif *nip; +{ + struct ip_nif *inp; + struct ipvcc *ivp; + u_long dstip = dst->sin_addr.s_addr; + int s; + + /* + * Look in cache first + */ + if (last_map_ipdst == dstip) + return (last_map_ipvcc); + + /* + * Oh well, we've got to search for it...first find the interface + */ + s = splnet(); + for (inp = ipatm_nif_head; inp; inp = inp->inf_next) { + if (inp->inf_nif == nip) + break; + } + if (inp == NULL) { + (void) splx(s); + return (NULL); + } + + /* + * Now home in on the VCC + */ + for (ivp = Q_HEAD(inp->inf_vcq, struct ipvcc); ivp; + ivp = Q_NEXT(ivp, struct ipvcc, iv_elem)) { + if (ivp->iv_dst.s_addr == dstip) + break; + } + + /* + * Update lookup cache + */ + if (ivp) { + last_map_ipdst = dstip; + last_map_ipvcc = ivp; + } + (void) splx(s); + + return (ivp); +} + diff --git a/sys/netatm/kern_include.h b/sys/netatm/kern_include.h new file mode 100644 index 0000000..9134206 --- /dev/null +++ b/sys/netatm/kern_include.h @@ -0,0 +1,112 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: kern_include.h,v 1.7 1998/07/23 21:44:40 root Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * Common kernel module includes + * + */ + +#ifndef _NETATM_KERN_INCLUDE_H +#define _NETATM_KERN_INCLUDE_H + +/* + * Note that we're compiling kernel code + */ +#define ATM_KERNEL + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/types.h> +#include <sys/errno.h> +#include <sys/malloc.h> +#include <sys/proc.h> +#include <sys/sockio.h> +#include <sys/time.h> +#include <sys/kernel.h> +#include <sys/conf.h> +#include <sys/domain.h> +#include <sys/protosw.h> +#include <sys/socket.h> +#include <sys/socketvar.h> +#include <sys/syslog.h> + +#ifdef sun +#include <machine/cpu.h> +#include <machine/mmu.h> +#include <machine/psl.h> +#include <sun/openprom.h> +#include <sun/vddrv.h> +#include <sundev/mbvar.h> +#endif + +#ifdef __FreeBSD__ +#include <machine/clock.h> +#include <vm/vm.h> +#include <vm/pmap.h> +#endif + +/* + * Networking support + */ +#include <net/if.h> +#if (defined(BSD) && (BSD >= 199103)) +#include <net/if_types.h> +#include <net/if_dl.h> +#endif +#include <net/netisr.h> +#include <net/route.h> +#include <netinet/in.h> +#include <netinet/in_var.h> +#include <netinet/if_ether.h> + +/* + * Porting fluff + */ +#include <netatm/port.h> + +/* + * ATM core services + */ +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_cm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_vc.h> +#include <netatm/atm_ioctl.h> +#include <netatm/atm_sigmgr.h> +#include <netatm/atm_stack.h> +#include <netatm/atm_pcb.h> +#include <netatm/atm_var.h> + +#endif /* _NETATM_KERN_INCLUDE_H */ diff --git a/sys/netatm/port.h b/sys/netatm/port.h new file mode 100644 index 0000000..fac693a --- /dev/null +++ b/sys/netatm/port.h @@ -0,0 +1,564 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: port.h,v 1.7 1998/03/24 20:25:28 mks Exp $ + * + */ + +/* + * System Configuration + * -------------------- + * + * Porting aides + * + */ + +#ifndef _NETATM_PORT_H +#define _NETATM_PORT_H + +/* + * Try to ensure that this system is supported + */ +#if (defined(BSD) && (BSD >= 199103)) + + /* 4.3 BSD Net2 based */ + +#elif defined(sun) + + /* SunOS4.x */ + +#else + + /* Ooops */ + #error "Undefined/unsupported system type" + +#endif + + +/* + * Kernel memory management + * + * KM_ALLOC(size, type, flags) + * Returns an allocated kernel memory chunk of size bytes. + * KM_FREE(addr, size, type) + * Free a kernel memory chunk of size bytes. + * KM_CMP(b1, b2, len) + * Compares len bytes of data from b1 against b2. + * KM_COPY(from, to, len) + * Copies len bytes of data from from to to. + * KM_ZERO(addr, len) + * Zeros len bytes of data from addr. + * + */ +#ifdef ATM_KERNEL +#if (defined(BSD) && (BSD >= 199103)) +#include <sys/malloc.h> +#define KM_ALLOC(size, type, flags) malloc((size), (type), (flags)) +#define KM_FREE(addr, size, type) free((addr), (type)) +#elif defined(sun) +#include <sys/kmem_alloc.h> +#define KM_ALLOC(size, type, flags) kmem_alloc(size) +#define KM_FREE(addr, size, type) kmem_free((addr), (size)) +#endif + +#if defined(BSD) +#define KM_CMP(b1, b2, len) bcmp((void *)(b1), (void *)(b2),\ + (len)) +#define KM_COPY(from, to, len) bcopy((void *)(from), (void *)(to),\ + (len)) +#define KM_ZERO(addr, len) bzero((void *)(addr), (len)) +#endif +#define XM_COPY(f, t, l) KM_COPY((f), (t), (l)) + +#else + +/* + * User-space memory management + * + * UM_ALLOC(size) Returns an allocated kernel memory chunk of size bytes. + * UM_FREE(addr) Free a kernel memory chunk of size bytes. + * UM_COPY(from, to, len) + * Copies len bytes of data from from to to. + * UM_ZERO(addr, len) Zeros len bytes of data from addr. + * + */ +#if (defined(BSD) && (BSD >= 199103)) +#define UM_ALLOC(size) malloc((size_t)(size)) +#define UM_FREE(addr) free((void *)(addr)) +#define UM_COPY(from, to, len) bcopy((void *)(from), (void *)(to),\ + (size_t)(len)) +#define UM_ZERO(addr, len) bzero((void *)(addr), (size_t)(len)) +#elif defined(sun) +#define UM_ALLOC(size) malloc(size) +#define UM_FREE(addr) free((char *)(addr)) +#define UM_COPY(from, to, len) bcopy((char *)(from), (char *)(to), (len)) +#define UM_ZERO(addr, len) bzero((char *)(addr), (len)) + +#endif +#define XM_COPY(f, t, l) UM_COPY((f), (t), (l)) + +#endif /* ATM_KERNEL */ + + +#ifdef ATM_KERNEL +/* + * Kernel buffers + * + * KBuffer Typedef for a kernel buffer. + * + * KB_NEXT(bfr) Access next buffer in chain (r/w). + * KB_LEN(bfr) Access length of data in this buffer (r/w). + * KB_QNEXT(bfr) Access next buffer in queue (r/w). + * + * KB_ALLOC(bfr, size, flags, type) + * Allocates a new kernel buffer of at least size bytes. + * KB_ALLOCPKT(bfr, size, flags, type) + * Allocates a new kernel packet header buffer of at + * least size bytes. + * KB_ALLOCEXT(bfr, size, flags, type) + * Allocates a new kernel buffer with external storage + * of at least size bytes. + * KB_FREEONE(bfr, nxt) Free buffer bfr and set next buffer in chain in nxt. + * KB_FREEALL(bfr) Free bfr's entire buffer chain. + * KB_COPY(bfr, off, len, new, flags) + * Copy len bytes of user data from buffer bfr starting at + * byte offset off and return new buffer chain in new. + * If len is KB_COPYALL, copy until end of chain. + * KB_COPYDATA(bfr, off, len, datap) + * Copy data from buffer bfr starting at byte offset off + * for len bytes into the data area pointed to by datap. + * Returns the number of bytes not copied to datap. + * KB_PULLUP(bfr, n, new) + * Get at least the first n bytes of data in the buffer + * chain headed by bfr contiguous in the first buffer. + * Returns the (potentially new) head of the chain in new. + * On failure the chain is freed and NULL is returned. + * KB_LINKHEAD(new, head) + * Link the kernel buffer new at the head of the buffer + * chain headed by head. If both new and head are + * packet header buffers, new will become the packet + * header for the chain. + * KB_LINK(new, prev) + * Link the kernel buffer new into the buffer chain + * after the buffer prev. + * KB_UNLINKHEAD(head, next) + * Unlink the kernel buffer from the head of the buffer + * chain headed by head. The buffer head will be freed + * and the new chain head will be placed in next. + * KB_UNLINK(old, prev, next) + * Unlink the kernel buffer old with previous buffer prev + * from its buffer chain. The following buffer in the + * chain will be placed in next and the buffer old will + * be freed. + * KB_ISPKT(bfr) Tests whether bfr is a packet header buffer. + * KB_ISEXT(bfr) Tests whether bfr has external storage. + * KB_BFRSTART(bfr, x, t) + * Sets x (cast to type t) to point to the start of the + * buffer space in bfr. + * KB_BFREND(bfr, x, t) + * Sets x (cast to type t) to point one byte past the end + * of the buffer space in bfr. + * KB_BFRLEN(bfr) Returns length of buffer space in bfr. + * KB_DATASTART(bfr, x, t) + * Sets x (cast to type t) to point to the start of the + * buffer data contained in bfr. + * KB_DATAEND(bfr, x, t) + * Sets x (cast to type t) to point one byte past the end + * of the buffer data contained in bfr. + * KB_HEADSET(bfr, n) Sets the start address for buffer data in buffer bfr to + * n bytes from the beginning of the buffer space. + * KB_HEADMOVE(bfr, n) Adjust buffer data controls to move data down (n > 0) + * or up (n < 0) n bytes in the buffer bfr. + * KB_HEADADJ(bfr, n) Adjust buffer data controls to add (n > 0) or subtract + * (n < 0) n bytes of data to/from the beginning of bfr. + * KB_TAILADJ(bfr, n) Adjust buffer data controls to add (n > 0) or subtract + * (n < 0) n bytes of data to/from the end of bfr. + * KB_TAILALIGN(bfr, n) Set buffer data controls to place an object of size n + * at the end of bfr, longword aligned. + * KB_HEADROOM(bfr, n) Set n to the amount of buffer space available before + * the start of data in bfr. + * KB_TAILROOM(bfr, n) Set n to the amount of buffer space available after + * the end of data in bfr. + * KB_PLENGET(bfr, n) Set n to bfr's packet length. + * KB_PLENSET(bfr, n) Set bfr's packet length to n. + * KB_PLENADJ(bfr, n) Adjust total packet length by n bytes. + * + */ +#if defined(BSD) +#include <sys/mbuf.h> +typedef struct mbuf KBuffer; + +#define KB_F_WAIT M_WAIT +#define KB_F_NOWAIT M_DONTWAIT + +#define KB_T_HEADER MT_HEADER +#define KB_T_DATA MT_DATA + +#define KB_COPYALL M_COPYALL + +#if BSD >= 199103 + +#define KB_NEXT(bfr) (bfr)->m_next +#define KB_LEN(bfr) (bfr)->m_len +#define KB_QNEXT(bfr) (bfr)->m_nextpkt +#define KB_ALLOC(bfr, size, flags, type) { \ + if ((size) <= MLEN) { \ + MGET((bfr), (flags), (type)); \ + } else \ + (bfr) = NULL; \ +} +#define KB_ALLOCPKT(bfr, size, flags, type) { \ + if ((size) <= MHLEN) { \ + MGETHDR((bfr), (flags), (type)); \ + } else \ + (bfr) = NULL; \ +} +#define KB_ALLOCEXT(bfr, size, flags, type) { \ + if ((size) <= MCLBYTES) { \ + MGET((bfr), (flags), (type)); \ + if ((bfr) != NULL) { \ + MCLGET((bfr), (flags)); \ + if (((bfr)->m_flags & M_EXT) == 0) { \ + m_freem((bfr)); \ + (bfr) = NULL; \ + } \ + } \ + } else \ + (bfr) = NULL; \ +} +#define KB_FREEONE(bfr, nxt) { \ + (nxt) = m_free(bfr); \ +} +#define KB_FREEALL(bfr) { \ + m_freem(bfr); \ +} +#define KB_COPY(bfr, off, len, new, flags) { \ + (new) = m_copym((bfr), (off), (len), (flags)); \ +} +#define KB_COPYDATA(bfr, off, len, datap) \ + (m_copydata((bfr), (off), (len), (datap)), 0) +#define KB_PULLUP(bfr, n, new) { \ + (new) = m_pullup((bfr), (n)); \ +} +#define KB_LINKHEAD(new, head) { \ + if ((head) && KB_ISPKT(new) && KB_ISPKT(head)) {\ + M_COPY_PKTHDR((new), (head)); \ + (head)->m_flags &= ~M_PKTHDR; \ + } \ + (new)->m_next = (head); \ +} +#define KB_LINK(new, prev) { \ + (new)->m_next = (prev)->m_next; \ + (prev)->m_next = (new); \ +} +#define KB_UNLINKHEAD(head, next) { \ + MFREE((head), (next)); \ +} +#define KB_UNLINK(old, prev, next) { \ + MFREE((old), (next)); \ + (prev)->m_next = (next); \ +} +#define KB_ISPKT(bfr) (((bfr)->m_flags & M_PKTHDR) != 0) +#define KB_ISEXT(bfr) (((bfr)->m_flags & M_EXT) != 0) +#define KB_BFRSTART(bfr, x, t) { \ + if ((bfr)->m_flags & M_EXT) \ + (x) = (t)((bfr)->m_ext.ext_buf); \ + else if ((bfr)->m_flags & M_PKTHDR) \ + (x) = (t)(&(bfr)->m_pktdat); \ + else \ + (x) = (t)((bfr)->m_dat); \ +} +#define KB_BFREND(bfr, x, t) { \ + if ((bfr)->m_flags & M_EXT) \ + (x) = (t)((bfr)->m_ext.ext_buf + (bfr)->m_ext.ext_size);\ + else if ((bfr)->m_flags & M_PKTHDR) \ + (x) = (t)(&(bfr)->m_pktdat + MHLEN); \ + else \ + (x) = (t)((bfr)->m_dat + MLEN); \ +} +#define KB_BFRLEN(bfr) \ + (((bfr)->m_flags & M_EXT) ? (bfr)->m_ext.ext_size : \ + (((bfr)->m_flags & M_PKTHDR) ? MHLEN : MLEN)) +#define KB_DATASTART(bfr, x, t) { \ + (x) = mtod((bfr), t); \ +} +#define KB_DATAEND(bfr, x, t) { \ + (x) = (t)(mtod((bfr), caddr_t) + (bfr)->m_len); \ +} +#define KB_HEADSET(bfr, n) { \ + if ((bfr)->m_flags & M_EXT) \ + (bfr)->m_data = (bfr)->m_ext.ext_buf + (n); \ + else if ((bfr)->m_flags & M_PKTHDR) \ + (bfr)->m_data = (bfr)->m_pktdat + (n); \ + else \ + (bfr)->m_data = (bfr)->m_dat + (n); \ +} +#define KB_HEADMOVE(bfr, n) { \ + (bfr)->m_data += (n); \ +} +#define KB_HEADADJ(bfr, n) { \ + (bfr)->m_len += (n); \ + (bfr)->m_data -= (n); \ +} +#define KB_TAILADJ(bfr, n) { \ + (bfr)->m_len += (n); \ +} +#define KB_TAILALIGN(bfr, n) { \ + (bfr)->m_len = (n); \ + if ((bfr)->m_flags & M_EXT) \ + (bfr)->m_data = (caddr_t)(((u_int)(bfr)->m_ext.ext_buf \ + + (bfr)->m_ext.ext_size - (n)) & ~(sizeof(long) - 1));\ + else \ + (bfr)->m_data = (caddr_t)(((u_int)(bfr)->m_dat + MLEN - (n)) \ + & ~(sizeof(long) - 1)); \ +} +#define KB_HEADROOM(bfr, n) { \ + /* n = M_LEADINGSPACE(bfr) XXX */ \ + (n) = ((bfr)->m_flags & M_EXT ? (bfr)->m_data - (bfr)->m_ext.ext_buf : \ + (bfr)->m_flags & M_PKTHDR ? (bfr)->m_data - (bfr)->m_pktdat : \ + (bfr)->m_data - (bfr)->m_dat); \ +} +#define KB_TAILROOM(bfr, n) { \ + (n) = M_TRAILINGSPACE(bfr); \ +} +#define KB_PLENGET(bfr, n) { \ + (n) = (bfr)->m_pkthdr.len; \ +} +#define KB_PLENSET(bfr, n) { \ + (bfr)->m_pkthdr.len = (n); \ +} +#define KB_PLENADJ(bfr, n) { \ + (bfr)->m_pkthdr.len += (n); \ +} + + +#else /* ! BSD >= 199103 */ + + +#define KB_NEXT(bfr) (bfr)->m_next +#define KB_LEN(bfr) (bfr)->m_len +#define KB_QNEXT(bfr) (bfr)->m_act +#define KB_ALLOC(bfr, size, flags, type) { \ + if ((size) <= MLEN) { \ + MGET((bfr), (flags), (type)); \ + } else \ + (bfr) = NULL; \ +} +#define KB_ALLOCPKT(bfr, size, flags, type) { \ + if ((size) <= MLEN) { \ + MGET((bfr), (flags), (type)); \ + } else \ + (bfr) = NULL; \ +} +#define KB_ALLOCEXT(bfr, size, flags, type) { \ + if ((size) <= MCLBYTES) { \ + MGET((bfr), (flags), (type)); \ + if ((bfr) != NULL) { \ + MCLGET(bfr); \ + if ((bfr)->m_len != MCLBYTES) { \ + m_freem((bfr)); \ + (bfr) = NULL; \ + } \ + } \ + } else \ + (bfr) = NULL; \ +} +#define KB_FREEONE(bfr, nxt) { \ + (nxt) = m_free(bfr); \ +} +#define KB_FREEALL(bfr) { \ + m_freem(bfr); \ +} +#define KB_COPY(bfr, off, len, new, flags) { \ + (new) = m_copy((bfr), (off), (len)); \ +} +#define KB_COPYDATA(bfr, off, len, datap) \ + m_cpytoc((bfr), (off), (len), (datap)) +#define KB_PULLUP(bfr, n, new) { \ + (new) = m_pullup((bfr), (n)); \ +} +#define KB_LINKHEAD(new, head) { \ + (new)->m_next = (head); \ +} +#define KB_LINK(new, prev) { \ + (new)->m_next = (prev)->m_next; \ + (prev)->m_next = (new); \ +} +#define KB_UNLINKHEAD(head, next) { \ + MFREE((head), (next)); \ +} +#define KB_UNLINK(old, prev, next) { \ + MFREE((old), (next)); \ + (prev)->m_next = (next); \ +} +#define KB_ISPKT(bfr) (0) +#define KB_ISEXT(bfr) M_HASCL(bfr) +#define KB_BFRSTART(bfr, x, t) { \ + if (M_HASCL(bfr)) { \ + if ((bfr)->m_cltype == MCL_STATIC) \ + (x) = (t)(mtod((bfr), int) & ~(MCLBYTES - 1)); \ + else \ + (x) = (t)NULL; \ + } else \ + (x) = (t)((bfr)->m_dat); \ +} +#define KB_BFREND(bfr, x, t) { \ + if (M_HASCL(bfr)) { \ + if ((bfr)->m_cltype == MCL_STATIC) \ + (x) = (t)((mtod((bfr), int) & ~(MCLBYTES - 1)) \ + + MCLBYTES); \ + else \ + (x) = (t)NULL; \ + } else \ + (x) = (t)((bfr)->m_dat + MLEN); \ +} +#define KB_BFRLEN(bfr) \ + (M_HASCL(bfr) ? (((bfr)->m_cltype == MCL_STATIC) ? MCLBYTES : 0) : MLEN) +#define KB_DATASTART(bfr, x, t) { \ + (x) = mtod((bfr), t); \ +} +#define KB_DATAEND(bfr, x, t) { \ + (x) = (t)(mtod((bfr), caddr_t) + (bfr)->m_len); \ +} +#define KB_HEADSET(bfr, n) { \ + if (M_HASCL(bfr)) { \ + /* Assume cluster buffer is empty XXX */\ + (bfr)->m_off += (n); \ + } else \ + (bfr)->m_off = MMINOFF + (n); \ +} +#define KB_HEADMOVE(bfr, n) { \ + (bfr)->m_off += (n); \ +} +#define KB_HEADADJ(bfr, n) { \ + (bfr)->m_len += (n); \ + (bfr)->m_off -= (n); \ +} +#define KB_TAILADJ(bfr, n) { \ + (bfr)->m_len += (n); \ +} +#define KB_TAILALIGN(bfr, n) { \ + (bfr)->m_len = (n); \ + if (M_HASCL(bfr)) { \ + if ((bfr)->m_cltype == MCL_STATIC) \ + (bfr)->m_off = (int)(((mtod((bfr), int) \ + & ~(MCLBYTES - 1)) + MCLBYTES - (n)) \ + & ~(sizeof(long) - 1)) - (int)(bfr); \ + /* Out of luck for loaned buffers */ \ + } else \ + (bfr)->m_off = (MMAXOFF - (n)) & ~(sizeof(long) - 1); \ +} +#define KB_HEADROOM(bfr, n) { \ + if (M_HASCL(bfr)) { \ + if ((bfr)->m_cltype == MCL_STATIC) \ + (n) = mtod((bfr), int) & (MCLBYTES - 1); \ + else \ + (n) = 0; \ + } else \ + (n) = (bfr)->m_off - MMINOFF; \ +} +#define KB_TAILROOM(bfr, n) { \ + if (M_HASCL(bfr)) { \ + if ((bfr)->m_cltype == MCL_STATIC) \ + (n) = MCLBYTES - ((mtod((bfr), int) + (bfr)->m_len) \ + & (MCLBYTES - 1)); \ + else \ + (n) = 0; \ + } else \ + (n) = MMAXOFF - ((bfr)->m_off + (bfr)->m_len); \ +} +#define KB_PLENGET(bfr, n) { \ + struct mbuf *zz; \ + for ((n) = 0, zz = (bfr); zz; zz = zz->m_next) \ + (n) += zz->m_len; \ +} +#define KB_PLENSET(bfr, n) { \ +} +#define KB_PLENADJ(bfr, n) { \ +} + + +#endif /* ! BSD >= 199103 */ + +#endif /* defined(BSD) */ + + +/* + * Kernel time + * + * KTimeout_ret Typedef for timeout() function return + * + * KT_TIME(t) Sets t to the current time. + * + */ +#if (defined(BSD) && (BSD >= 199306)) +typedef void KTimeout_ret; +#else +typedef int KTimeout_ret; +#endif +#if (defined(BSD) && (BSD >= 199103)) +#define KT_TIME(t) microtime(&t) +#elif defined(sun) +#define KT_TIME(t) uniqtime(&t) +#else +#define KT_TIME(t) ((t) = time) +#endif + +#endif /* ATM_KERNEL */ + +#ifndef NTOHL +#if BYTE_ORDER == BIG_ENDIAN +#define NTOHL(x) (x) +#define NTOHS(x) (x) +#define HTONL(x) (x) +#define HTONS(x) (x) +#else +#define NTOHL(x) (x) = ntohl((u_long)(x)) +#define NTOHS(x) (x) = ntohs((u_short)(x)) +#define HTONL(x) (x) = htonl((u_long)(x)) +#define HTONS(x) (x) = htons((u_short)(x)) +#endif +#endif /* NTOHL */ + +#ifndef MAX +#define MAX(a,b) max((a),(b)) +#endif +#ifndef MIN +#define MIN(a,b) min((a),(b)) +#endif + +#if (!(defined(BSD) && (BSD >= 199306))) +#ifndef __BIT_TYPES_DEFINED__ +#define __BIT_TYPES_DEFINED__ +typedef char int8_t; +typedef unsigned char u_int8_t; +typedef short int16_t; +typedef unsigned short u_int16_t; +typedef int int32_t; +typedef unsigned int u_int32_t; +#endif +#endif + +#endif /* _NETATM_PORT_H */ diff --git a/sys/netatm/queue.h b/sys/netatm/queue.h new file mode 100644 index 0000000..8a8febf --- /dev/null +++ b/sys/netatm/queue.h @@ -0,0 +1,213 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: queue.h,v 1.2 1997/05/06 22:14:38 mks Exp $ + * + */ + +/* + * Core ATM Services + * ----------------- + * + * General queueing/linking definitions + * + */ + +#ifndef _NETATM_QUEUE_H +#define _NETATM_QUEUE_H + +/* + * Structure defining the queue controls for a doubly linked queue + */ +struct q_queue { + caddr_t q_head; /* Head of queue */ + caddr_t q_tail; /* Tail of queue */ +}; +typedef struct q_queue Queue_t; + +/* + * Structure defining the queue elements of a doubly linked queue + */ +struct q_elem { + caddr_t q_forw; /* Forward link */ + caddr_t q_back; /* Backward link */ +}; +typedef struct q_elem Qelem_t; + +/* + * Macro to add a control block onto the tail of a doubly linked queue + * e = control block to add + * t = control block structure type + * el = name of control block's q_elem field + * q = pointer to queue controls + */ +#define ENQUEUE(e,t,el,q) \ +{ \ + (e)->el.q_forw = NULL; \ + (e)->el.q_back = (q).q_tail; \ + if ((q).q_head == NULL) { \ + (q).q_head = (caddr_t)(e); \ + (q).q_tail = (caddr_t)(e); \ + } else { \ + ((t *)(q).q_tail)->el.q_forw = (caddr_t)(e); \ + (q).q_tail = (caddr_t)(e); \ + } \ +} + +/* + * Macro to remove a control block from a doubly linked queue + * e = control block to remove + * t = control block structure type + * el = name of control block's q_elem field + * q = pointer to queue controls + */ +#define DEQUEUE(e,t,el,q) \ +{ \ + /* Ensure control block is on queue */ \ + if ((e)->el.q_forw || (q).q_tail == (caddr_t)(e)) { \ + if ((e)->el.q_forw) \ + ((t *)(e)->el.q_forw)->el.q_back = (e)->el.q_back;\ + else \ + (q).q_tail = (e)->el.q_back; \ + if ((e)->el.q_back) \ + ((t *)(e)->el.q_back)->el.q_forw = (e)->el.q_forw;\ + else \ + (q).q_head = (e)->el.q_forw; \ + } \ + (e)->el.q_back = (e)->el.q_forw = NULL; \ +} + +/* + * Macro to return the head of a doubly linked queue + * q = pointer to queue controls + * t = control block structure type + */ +#define Q_HEAD(q,t) ((t *)(q).q_head) + +/* + * Macro to return the next control block of a doubly linked queue + * e = current control block + * t = control block structure type + * el = name of control block's q_elem field + */ +#define Q_NEXT(e,t,el) ((t *)(e)->el.q_forw) + + +/* + * Macro to add a control block onto the head of a singly linked chain + * u = control block to add + * t = structure type + * h = head of chain + * l = name of link field + */ +#define LINK2HEAD(u,t,h,l) \ +{ \ + (u)->l = (h); \ + (h) = (u); \ +} + +/* + * Macro to add a control block onto the tail of a singly linked chain + * u = control block to add + * t = structure type + * h = head of chain + * l = name of link field + */ +#define LINK2TAIL(u,t,h,l) \ +{ \ + (u)->l = (t *)NULL; \ + /* Check for empty chain */ \ + if ((h) == (t *)NULL) { \ + (h) = (u); \ + } else { \ + t *tp; \ + /* Loop until we find the end of chain */ \ + for (tp = (h); tp->l != (t *)NULL; tp = tp->l) \ + ; \ + tp->l = (u); \ + } \ +} + +/* + * Macro to remove a control block from a singly linked chain + * u = control block to unlink + * t = structure type + * h = head of chain + * l = name of link field + */ +#define UNLINK(u,t,h,l) \ +{ \ + /* Check for control block at head of chain */ \ + if ((u) == (h)) { \ + (h) = (u)->l; \ + } else { \ + t *tp; \ + /* Loop until we find the control block */ \ + for (tp = (h); tp != (t *)NULL; tp = tp->l) { \ + if (tp->l == (u)) \ + break; \ + } \ + if (tp) { \ + /* Remove it from chain */ \ + tp->l = (u)->l; \ + } \ + } \ + (u)->l = (t *)NULL; \ +} + +/* + * Macro to remove a control block from a singly linked chain and return + * an indication of whether the block was found + * u = control block to unlink + * t = structure type + * h = head of chain + * l = name of link field + * f = flag; 1 => control block found on chain; else 0 + */ +#define UNLINKF(u,t,h,l,f) \ +{ \ + /* Check for control block at head of chain */ \ + if ((u) == (h)) { \ + (h) = (u)->l; \ + (f) = 1; \ + } else { \ + t *tp; \ + /* Loop until we find the control block */ \ + for (tp = (h); tp != (t *)NULL; tp = tp->l) { \ + if (tp->l == (u)) \ + break; \ + } \ + if (tp) { \ + /* Remove it from chain */ \ + tp->l = (u)->l; \ + (f) = 1; \ + } else \ + /* It wasn't on the chain */ \ + (f) = 0; \ + } \ + (u)->l = (t *)NULL; \ +} + +#endif /* _NETATM_QUEUE_H */ diff --git a/sys/netatm/sigpvc/sigpvc.h b/sys/netatm/sigpvc/sigpvc.h new file mode 100644 index 0000000..893a682 --- /dev/null +++ b/sys/netatm/sigpvc/sigpvc.h @@ -0,0 +1,47 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sigpvc.h,v 1.2 1997/05/06 22:15:43 mks Exp $ + * + */ + +/* + * PVC-only Signalling Manager + * --------------------------- + * + * Protocol definitions + * + */ + +#ifndef _SIGPVC_SIGPVC_H +#define _SIGPVC_SIGPVC_H + +/* + * Protocol Variables + */ +#define SIGPVC_DOWN_DELAY (15 * ATM_HZ) /* Delay til i/f marked down */ +#define SIGPVC_UP_DELAY (5 * ATM_HZ) /* Delay til i/f marked up */ + +#endif /* _SIGPVC_SIGPVC_H */ diff --git a/sys/netatm/sigpvc/sigpvc_if.c b/sys/netatm/sigpvc/sigpvc_if.c new file mode 100644 index 0000000..4208f29 --- /dev/null +++ b/sys/netatm/sigpvc/sigpvc_if.c @@ -0,0 +1,953 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sigpvc_if.c,v 1.13 1998/07/30 22:32:42 mks Exp $ + * + */ + +/* + * PVC-only Signalling Manager + * --------------------------- + * + * External interfaces to SigPVC manager. Includes support for + * running as a loadable kernel module. + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sigpvc_if.c,v 1.13 1998/07/30 22:32:42 mks Exp $"; +#endif + +#ifndef ATM_SIGPVC_MODULE +#include "opt_atm.h" +#endif + +#include <netatm/kern_include.h> + +#include <netatm/sigpvc/sigpvc.h> +#include <netatm/sigpvc/sigpvc_var.h> + + +/* + * Global variables + */ +struct sp_info sigpvc_vcpool = { + "sigpvc vcc pool", /* si_name */ + sizeof(struct sigpvc_vccb), /* si_blksiz */ + 10, /* si_blkcnt */ + 50 /* si_maxallow */ +}; + +/* + * Local functions + */ +static int sigpvc_start __P((void)); +static int sigpvc_stop __P((void)); +static int sigpvc_attach __P((struct sigmgr *, struct atm_pif *)); +static int sigpvc_detach __P((struct atm_pif *)); +static int sigpvc_setup __P((Atm_connvc *, int *)); +static int sigpvc_release __P((struct vccb *, int *)); +static int sigpvc_free __P((struct vccb *)); +static int sigpvc_ioctl __P((int, caddr_t, caddr_t)); + +/* + * Local variables + */ +static int sigpvc_registered = 0; +static struct sigmgr sigpvc_mgr = { + NULL, + ATM_SIG_PVC, + NULL, + sigpvc_attach, + sigpvc_detach, + sigpvc_setup, + NULL, + NULL, + sigpvc_release, + sigpvc_free, + sigpvc_ioctl +}; + +static struct attr_cause sigpvc_cause = { + T_ATM_PRESENT, + { + T_ATM_ITU_CODING, + T_ATM_LOC_USER, + T_ATM_CAUSE_UNSPECIFIED_NORMAL, + {0, 0, 0, 0} + } +}; + + +/* + * Initialize sigpvc processing + * + * This will be called during module loading. We'll just register + * the sigpvc protocol descriptor and wait for a SigPVC ATM interface + * to come online. + * + * Arguments: + * none + * + * Returns: + * 0 startup was successful + * errno startup failed - reason indicated + * + */ +static int +sigpvc_start() +{ + int err = 0; + + /* + * Verify software version + */ + if (atm_version != ATM_VERSION) { + log(LOG_ERR, "version mismatch: sigpvc=%d.%d kernel=%d.%d\n", + ATM_VERS_MAJ(ATM_VERSION), ATM_VERS_MIN(ATM_VERSION), + ATM_VERS_MAJ(atm_version), ATM_VERS_MIN(atm_version)); + return (EINVAL); + } + + /* + * Register ourselves with system + */ + err = atm_sigmgr_register(&sigpvc_mgr); + if (err == 0) + sigpvc_registered = 1; + + return (err); +} + + +/* + * Halt sigpvc processing + * + * This should be called just prior to unloading the module from + * memory. All sigpvc interfaces must be deregistered before the + * protocol can be shutdown. + * + * Arguments: + * none + * + * Returns: + * 0 shutdown was successful + * errno shutdown failed - reason indicated + * + */ +static int +sigpvc_stop() +{ + int err = 0; + int s = splnet(); + + /* + * Is protocol even setup? + */ + if (sigpvc_registered) { + + /* + * Any protocol instances still registered?? + */ + if (sigpvc_mgr.sm_prinst) { + + /* Yes, can't stop now */ + err = EBUSY; + goto done; + } + + /* + * De-register from system + */ + err = atm_sigmgr_deregister(&sigpvc_mgr); + sigpvc_registered = 0; + + /* + * Free up our vccb storage pool + */ + atm_release_pool(&sigpvc_vcpool); + } else + err = ENXIO; + +done: + (void) splx(s); + return (err); +} + + +/* + * Attach a SigPVC-controlled interface + * + * Each ATM physical interface must be attached with the signalling manager for + * the interface's signalling protocol (via the atm_sigmgr_attach function). + * This function will handle the attachment for SigPVC-controlled interfaces. + * A new sigpvc protocol instance will be created and then we'll just sit + * around waiting for connection requests. + * + * Function must be called at splnet. + * + * Arguments: + * smp pointer to sigpvc signalling manager control block + * pip pointer to atm physical interface control block + * + * Returns: + * 0 attach successful + * errno attach failed - reason indicated + * + */ +static int +sigpvc_attach(smp, pip) + struct sigmgr *smp; + struct atm_pif *pip; +{ + int err = 0; + struct sigpvc *pvp = NULL; + + /* + * Allocate sigpvc protocol instance control block + */ + pvp = (struct sigpvc *) + KM_ALLOC(sizeof(struct sigpvc), M_DEVBUF, M_NOWAIT); + if (pvp == NULL) { + err = ENOMEM; + goto done; + } + KM_ZERO(pvp, sizeof(struct sigpvc)); + + /* + * Link instance into manager's chain + */ + LINK2TAIL((struct siginst *)pvp, struct siginst, + smp->sm_prinst, si_next); + + /* + * Finally, set state and link in interface + */ + pvp->pv_pif = pip; + pvp->pv_state = SIGPVC_ACTIVE; + pip->pif_sigmgr = smp; + pip->pif_siginst = (struct siginst *)pvp; + +done: + /* + * Reset our work if attach fails + */ + if (err) { + pip->pif_sigmgr = NULL; + pip->pif_siginst = NULL; + if (pvp) { + UNLINK((struct siginst *)pvp, struct siginst, + smp->sm_prinst, si_next); + KM_FREE(pvp, sizeof(struct sigpvc), M_DEVBUF); + } + } + + return (err); +} + + +/* + * Detach a SigPVC-controlled interface + * + * Each ATM physical interface may be detached from its signalling manager + * (via the atm_sigmgr_detach function). This function will handle the + * detachment for all SigPVC-controlled interfaces. All circuits will be + * immediately terminated. + * + * Function must be called at splnet. + * + * Arguments: + * pip pointer to atm physical interface control block + * + * Returns: + * 0 detach successful + * errno detach failed - reason indicated + * + */ +static int +sigpvc_detach(pip) + struct atm_pif *pip; +{ + struct sigpvc *pvp; + struct vccb *vcp, *vnext; + + /* + * Get SigPVC protocol instance + */ + pvp = (struct sigpvc *)pip->pif_siginst; + + /* + * Terminate all of our VCCs + */ + for (vcp = Q_HEAD(pvp->pv_vccq, struct vccb); vcp; vcp = vnext){ + u_char oustate; + + vnext = Q_NEXT(vcp, struct vccb, vc_sigelem); + + /* + * Close VCC and notify owner + */ + oustate = vcp->vc_ustate; + sigpvc_close_vcc(vcp); + if (oustate == VCCU_OPEN) { + vcp->vc_connvc->cvc_attr.cause = sigpvc_cause; + atm_cm_cleared(vcp->vc_connvc); + } + } + + /* + * If there are no vcc's queued, then get rid of the protocol + * instance. + */ + if (Q_HEAD(pvp->pv_vccq, struct vccb) == NULL) { + struct sigmgr *smp = pip->pif_sigmgr; + + pip->pif_sigmgr = NULL; + pip->pif_siginst = NULL; + UNLINK((struct siginst *)pvp, struct siginst, smp->sm_prinst, + si_next); + KM_FREE(pvp, sizeof(struct sigpvc), M_DEVBUF); + } else { + + /* + * Otherwise, set new state indicating detach in progress. + * The protocol instance will be freed during sigpvc_free + * processing for the last queued vcc. + */ + pvp->pv_state = SIGPVC_DETACH; + } + + return (0); +} + + +/* + * Open a SigPVC ATM Connection + * + * All service user requests to open a VC connection (via atm_open_connection) + * over an ATM interface attached to the SigPVC signalling manager are handled + * here. Only PVC requests are allowed. + * + * Function will be called at splnet. + * + * Arguments: + * cvp pointer to CM's connection VCC + * errp location to store an error code if CALL_FAILED is returned + * + * Returns: + * CALL_PROCEEDING - connection establishment is in progress + * CALL_FAILED - connection establishment failed + * CALL_CONNECTED - connection has been successfully established + * + */ +static int +sigpvc_setup(cvp, errp) + Atm_connvc *cvp; + int *errp; +{ + struct sigpvc *pvp = + (struct sigpvc *)cvp->cvc_attr.nif->nif_pif->pif_siginst; + int ret; + + /* + * See what signalling has to say + */ + switch (pvp->pv_state) { + + case SIGPVC_ACTIVE: + break; + + default: + *errp = ENXIO; + ret = CALL_FAILED; + goto done; + } + + /* + * Open requested type of connection + */ + switch (cvp->cvc_attr.called.addr.address_format) { + + case T_ATM_PVC_ADDR: + /* + * Create a PVC + */ + ret = sigpvc_create_pvc(pvp, cvp, errp); + break; + + default: + *errp = EPROTONOSUPPORT; + ret = CALL_FAILED; + } + +done: + return (ret); +} + + +/* + * Close a SigPVC ATM Connection + * + * All service user requests to terminate a previously open VC connection + * (via the atm_close_connection function), which is running over an interface + * attached to the SigPVC signalling manager, are handled here. + * + * Function will be called at splnet. + * + * Arguments: + * vcp pointer to connection's VC control block + * errp location to store an error code if CALL_FAILED is returned + * + * Returns: + * CALL_PROCEEDING - connection termination is in progress + * CALL_FAILED - connection termination failed + * CALL_CLEARED - connection has been successfully terminated + * + */ +static int +sigpvc_release(vcp, errp) + struct vccb *vcp; + int *errp; +{ + + /* + * Make sure VCC is open + */ + if ((vcp->vc_sstate == VCCS_NULL) || (vcp->vc_sstate == VCCS_FREE) || + (vcp->vc_ustate == VCCU_NULL) || (vcp->vc_ustate == VCCU_CLOSED)) { + *errp = EALREADY; + return (CALL_FAILED); + } + + /* + * Not much else to do except close the vccb + */ + sigpvc_close_vcc(vcp); + + return (CALL_CLEARED); +} + + +/* + * Free SigPVC ATM Connection Resources + * + * All service user requests to free the resources of a closed VCC connection + * (via the atm_free_connection function), which is running over an interface + * attached to the SigPVC signalling manager, are handled here. + * + * Function will be called at splnet. + * + * Arguments: + * vcp pointer to connection's VCC control block + * + * Returns: + * 0 connection free was successful + * errno connection free failed - reason indicated + * + */ +static int +sigpvc_free(vcp) + struct vccb *vcp; +{ + struct atm_pif *pip = vcp->vc_pif; + struct sigpvc *pvp = (struct sigpvc *)pip->pif_siginst; + + /* + * Make sure VCC has been closed + */ + if ((vcp->vc_ustate != VCCU_CLOSED) || (vcp->vc_sstate != VCCS_FREE)) + return (EEXIST); + + /* + * Remove vccb from protocol queue + */ + DEQUEUE(vcp, struct vccb, vc_sigelem, pvp->pv_vccq); + + /* + * Free vccb storage + */ + vcp->vc_ustate = VCCU_NULL; + vcp->vc_sstate = VCCS_NULL; + atm_free((caddr_t)vcp); + + /* + * If we're detaching and this was the last vcc queued, + * get rid of the protocol instance + */ + if ((pvp->pv_state == SIGPVC_DETACH) && + (Q_HEAD(pvp->pv_vccq, struct vccb) == NULL)) { + struct sigmgr *smp = pip->pif_sigmgr; + + pip->pif_sigmgr = NULL; + pip->pif_siginst = NULL; + UNLINK((struct siginst *)pvp, struct siginst, smp->sm_prinst, + si_next); + KM_FREE(pvp, sizeof(struct sigpvc), M_DEVBUF); + } + + return (0); +} + + +/* + * Process Signalling Manager PF_ATM ioctls + * + * Function will be called at splnet. + * + * Arguments: + * code PF_ATM sub-operation code + * data pointer to code specific parameter data area + * arg1 pointer to code specific argument + * + * Returns: + * 0 request procesed + * errno error processing request - reason indicated + * + */ +static int +sigpvc_ioctl(code, data, arg1) + int code; + caddr_t data; + caddr_t arg1; +{ + struct atmdelreq *adp; + struct atminfreq *aip; + struct air_vcc_rsp avr; + struct sigpvc *pvp; + struct vccb *vcp; + Atm_connection *cop; + caddr_t cp; + u_int vpi, vci; + int i, space, err = 0; + + + switch (code) { + + case AIOCS_DEL_PVC: + /* + * Delete a PVC + */ + adp = (struct atmdelreq *)data; + pvp = (struct sigpvc *)arg1; + + /* + * Find requested VCC + */ + vpi = adp->adr_pvc_vpi; + vci = adp->adr_pvc_vci; + for (vcp = Q_HEAD(pvp->pv_vccq, struct vccb); vcp; + vcp = Q_NEXT(vcp, struct vccb, vc_sigelem)) { + if ((vcp->vc_vpi == vpi) && (vcp->vc_vci == vci)) + break; + } + if (vcp == NULL) + return (ENOENT); + + /* + * Schedule VCC termination + */ + err = atm_cm_abort(vcp->vc_connvc, &sigpvc_cause.v); + break; + + case AIOCS_DEL_SVC: + /* + * Delete a SVC + */ + err = ENOENT; + break; + + case AIOCS_INF_VCC: + /* + * Get VCC information + */ + aip = (struct atminfreq *)data; + pvp = (struct sigpvc *)arg1; + + cp = aip->air_buf_addr; + space = aip->air_buf_len; + + /* + * Get info for all VCCs on interface + */ + for (vcp = Q_HEAD(pvp->pv_vccq, struct vccb); vcp; + vcp = Q_NEXT(vcp, struct vccb, vc_sigelem)) { + /* + * Make sure there's room in user buffer + */ + if (space < sizeof(avr)) { + err = ENOSPC; + break; + } + + /* + * Fill in info to be returned + */ + (void) sprintf(avr.avp_intf, "%s%d", + pvp->pv_pif->pif_name, pvp->pv_pif->pif_unit); + avr.avp_vpi = vcp->vc_vpi; + avr.avp_vci = vcp->vc_vci; + avr.avp_type = vcp->vc_type; + avr.avp_sig_proto = ATM_SIG_PVC; + avr.avp_aal = vcp->vc_connvc->cvc_attr.aal.type; + cop = vcp->vc_connvc->cvc_conn; + if (cop) + avr.avp_encaps = cop->co_mpx; + else + avr.avp_encaps = 0; + KM_ZERO(avr.avp_owners, sizeof(avr.avp_owners)); + for (i = 0; cop && i < sizeof(avr.avp_owners); + cop = cop->co_next, + i += T_ATM_APP_NAME_LEN+1) { + strncpy(&avr.avp_owners[i], + cop->co_endpt->ep_getname(cop->co_toku), + T_ATM_APP_NAME_LEN); + } + avr.avp_state = vcp->vc_sstate; + avr.avp_daddr.address_format = T_ATM_ABSENT; + avr.avp_dsubaddr.address_format = T_ATM_ABSENT; + avr.avp_ipdus = vcp->vc_ipdus; + avr.avp_opdus = vcp->vc_opdus; + avr.avp_ibytes = vcp->vc_ibytes; + avr.avp_obytes = vcp->vc_obytes; + avr.avp_ierrors = vcp->vc_ierrors; + avr.avp_oerrors = vcp->vc_oerrors; + avr.avp_tstamp = vcp->vc_tstamp; + + /* + * Copy data to user buffer and update buffer info + */ + if (err = copyout((caddr_t)&avr, cp, sizeof(avr))) + break; + cp += sizeof(avr); + space -= sizeof(avr); + } + + /* + * Update buffer pointer/count + */ + aip->air_buf_addr = cp; + aip->air_buf_len = space; + break; + + case AIOCS_INF_ARP: + /* + * Get ARP table information + */ + /* We don't maintain any ARP information */ + break; + + default: + err = EOPNOTSUPP; + } + + return (err); +} + + +#ifdef ATM_SIGPVC_MODULE +/* + ******************************************************************* + * + * Loadable Module Support + * + ******************************************************************* + */ +static int sigpvc_doload __P((void)); +static int sigpvc_dounload __P((void)); + +/* + * Generic module load processing + * + * This function is called by an OS-specific function when this + * module is being loaded. + * + * Arguments: + * none + * + * Returns: + * 0 load was successful + * errno load failed - reason indicated + * + */ +static int +sigpvc_doload() +{ + int err = 0; + + /* + * Start us up + */ + err = sigpvc_start(); + if (err) + /* Problems, clean up */ + (void)sigpvc_stop(); + + return (err); +} + + +/* + * Generic module unload processing + * + * This function is called by an OS-specific function when this + * module is being unloaded. + * + * Arguments: + * none + * + * Returns: + * 0 unload was successful + * errno unload failed - reason indicated + * + */ +static int +sigpvc_dounload() +{ + int err = 0; + + /* + * OK, try to clean up our mess + */ + err = sigpvc_stop(); + + return (err); +} + + +#ifdef sun +/* + * Loadable driver description + */ +struct vdldrv sigpvc_drv = { + VDMAGIC_PSEUDO, /* Pseudo Driver */ + "sigpvc_mod", /* name */ + NULL, /* dev_ops */ + NULL, /* bdevsw */ + NULL, /* cdevsw */ + 0, /* blockmajor */ + 0 /* charmajor */ +}; + + +/* + * Loadable module support entry point + * + * This is the routine called by the vd driver for all loadable module + * functions for this pseudo driver. This routine name must be specified + * on the modload(1) command. This routine will be called whenever the + * modload(1), modunload(1) or modstat(1) commands are issued for this + * module. + * + * Arguments: + * cmd vd command code + * vdp pointer to vd driver's structure + * vdi pointer to command-specific vdioctl_* structure + * vds pointer to status structure (VDSTAT only) + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +int +sigpvc_mod(cmd, vdp, vdi, vds) + int cmd; + struct vddrv *vdp; + caddr_t vdi; + struct vdstat *vds; +{ + int err = 0; + + switch (cmd) { + + case VDLOAD: + /* + * Module Load + * + * We dont support any user configuration + */ + err = sigpvc_doload(); + if (err == 0) + /* Let vd driver know about us */ + vdp->vdd_vdtab = (struct vdlinkage *)&sigpvc_drv; + break; + + case VDUNLOAD: + /* + * Module Unload + */ + err = sigpvc_dounload(); + break; + + case VDSTAT: + /* + * Module Status + */ + + /* Not much to say at the moment */ + + break; + + default: + log(LOG_ERR, "sigpvc_mod: Unknown vd command 0x%x\n", cmd); + err = EINVAL; + } + + return (err); +} +#endif /* sun */ + +#ifdef __FreeBSD__ + +#include <sys/exec.h> +#include <sys/sysent.h> +#include <sys/lkm.h> + +/* + * Loadable miscellaneous module description + */ +MOD_MISC(sigpvc); + + +/* + * Loadable module support "load" entry point + * + * This is the routine called by the lkm driver whenever the + * modload(1) command is issued for this module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +static int +sigpvc_load(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + return(sigpvc_doload()); +} + + +/* + * Loadable module support "unload" entry point + * + * This is the routine called by the lkm driver whenever the + * modunload(1) command is issued for this module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +static int +sigpvc_unload(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + return(sigpvc_dounload()); +} + + +/* + * Loadable module support entry point + * + * This is the routine called by the lkm driver for all loadable module + * functions for this driver. This routine name must be specified + * on the modload(1) command. This routine will be called whenever the + * modload(1), modunload(1) or modstat(1) commands are issued for this + * module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * ver lkm version + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +int +sigpvc_mod(lkmtp, cmd, ver) + struct lkm_table *lkmtp; + int cmd; + int ver; +{ + MOD_DISPATCH(sigpvc, lkmtp, cmd, ver, + sigpvc_load, sigpvc_unload, lkm_nullcmd); +} +#endif /* __FreeBSD__ */ + +#else /* !ATM_SIGPVC_MODULE */ + +/* + ******************************************************************* + * + * Kernel Compiled Module Support + * + ******************************************************************* + */ +static void sigpvc_doload __P((void *)); + +SYSINIT(atmsigpvc, SI_SUB_PROTO_END, SI_ORDER_ANY, sigpvc_doload, NULL) + +/* + * Kernel initialization + * + * Arguments: + * arg Not used + * + * Returns: + * none + * + */ +static void +sigpvc_doload(void *arg) +{ + int err = 0; + + /* + * Start us up + */ + err = sigpvc_start(); + if (err) { + /* Problems, clean up */ + (void)sigpvc_stop(); + + log(LOG_ERR, "ATM SIGPVC unable to initialize (%d)!!\n", err); + } + return; +} +#endif /* ATM_SIGPVC_MODULE */ + diff --git a/sys/netatm/sigpvc/sigpvc_subr.c b/sys/netatm/sigpvc/sigpvc_subr.c new file mode 100644 index 0000000..00f92ec --- /dev/null +++ b/sys/netatm/sigpvc/sigpvc_subr.c @@ -0,0 +1,181 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sigpvc_subr.c,v 1.7 1998/06/29 21:52:25 mks Exp $ + * + */ + +/* + * PVC-only Signalling Manager + * --------------------------- + * + * Subroutines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sigpvc_subr.c,v 1.7 1998/06/29 21:52:25 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/sigpvc/sigpvc.h> +#include <netatm/sigpvc/sigpvc_var.h> + +extern struct sp_info sigpvc_vcpool; + +/* + * Create a SigPVC Permanent Virtual Channel + * + * This function will construct a vccb for a "sigpvc-controlled" PVC + * and create the service stack requested by the user. + * + * Must be called at splnet. + * + * Arguments: + * pvp pointer to sigpvc protocol instance + * cvp pointer to CM's connection VCC + * errp location to store an error code if CALL_FAILED is returned + * + * Returns: + * CALL_FAILED - pvc creation failed + * CALL_CONNECTED - pvc has been successfully created + * + */ +int +sigpvc_create_pvc(pvp, cvp, errp) + struct sigpvc *pvp; + Atm_connvc *cvp; + int *errp; +{ + Atm_addr_pvc *pp; + struct vccb *vcp; + u_int vpi, vci; + + pp = (Atm_addr_pvc *)cvp->cvc_attr.called.addr.address; + vpi = ATM_PVC_GET_VPI(pp); + vci = ATM_PVC_GET_VCI(pp); + + /* + * Verify requested VPI,VCI + */ + if ((vpi > pvp->pv_pif->pif_maxvpi) || + (vci == 0) || (vci > pvp->pv_pif->pif_maxvci)) { + *errp = ERANGE; + return (CALL_FAILED); + } + + for (vcp = Q_HEAD(pvp->pv_vccq, struct vccb); vcp; + vcp = Q_NEXT(vcp, struct vccb, vc_sigelem)) { + + if ((vcp->vc_vpi == vpi) && + (vcp->vc_vci == vci)) { + *errp = EADDRINUSE; + return (CALL_FAILED); + } + } + + /* + * Verify network interface + */ + if (cvp->cvc_attr.nif) { + if (cvp->cvc_attr.nif->nif_pif != pvp->pv_pif) { + *errp = EINVAL; + return (CALL_FAILED); + } + } + + /* + * Allocate control block for PVC + */ + vcp = (struct vccb *)atm_allocate(&sigpvc_vcpool); + if (vcp == NULL) { + *errp = ENOMEM; + return (CALL_FAILED); + } + + /* + * Fill in VCCB + */ + vcp->vc_type = VCC_PVC | VCC_IN | VCC_OUT; + vcp->vc_proto = ATM_SIG_PVC; + vcp->vc_sstate = VCCS_ACTIVE; + vcp->vc_ustate = VCCU_OPEN; + vcp->vc_pif = pvp->pv_pif; + vcp->vc_nif = cvp->cvc_attr.nif; + vcp->vc_vpi = vpi; + vcp->vc_vci = vci; + vcp->vc_connvc = cvp; + + /* + * Put VCCB on sigpvc queue + */ + ENQUEUE(vcp, struct vccb, vc_sigelem, pvp->pv_vccq); + + /* + * Pass back VCCB to connection manager + */ + cvp->cvc_vcc = vcp; + + /* + * PVC is ready to go! + */ + return (CALL_CONNECTED); +} + +/* + * Close a SigPVC VCC + * + * Clean up vccb, note that it's closing and wait for its freeing. + * + * Arguments: + * vcp pointer to connection's VCC control block + * + * Returns: + * none + * + */ +void +sigpvc_close_vcc(vcp) + struct vccb *vcp; +{ + + /* + * Sanity check (actually design-flaw check) + */ + if (vcp->vc_connvc->cvc_upcnt || vcp->vc_connvc->cvc_downcnt) + panic("sigpvc_close_vcc: stack call"); + + /* + * Set state variables + */ + vcp->vc_ustate = VCCU_CLOSED; + vcp->vc_sstate = VCCS_FREE; + + /* + * Wait for user to free resources + */ +} + diff --git a/sys/netatm/sigpvc/sigpvc_var.h b/sys/netatm/sigpvc/sigpvc_var.h new file mode 100644 index 0000000..24f92c0 --- /dev/null +++ b/sys/netatm/sigpvc/sigpvc_var.h @@ -0,0 +1,95 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sigpvc_var.h,v 1.5 1998/02/19 20:16:28 mks Exp $ + * + */ + +/* + * PVC-only Signalling Manager + * --------------------------- + * + * Protocol control blocks + * + */ + +#ifndef _SIGPVC_SIGPVC_VAR_H +#define _SIGPVC_SIGPVC_VAR_H + +#ifdef ATM_KERNEL +/* + * Structure containing state information for each SigPVC protocol instance. + * There will be one instance for each ATM device interface using the SigPVC + * signalling manager. + */ +struct sigpvc { + struct siginst pv_inst; /* Common header */ +}; +#define pv_next pv_inst.si_next +#define pv_pif pv_inst.si_pif +#define pv_addr pv_inst.si_addr +#define pv_vccq pv_inst.si_vccq +#define pv_state pv_inst.si_state +#endif /* ATM_KERNEL */ + +/* + * SigPVC Protocol States + */ +#define SIGPVC_ACTIVE 1 /* Active */ +#define SIGPVC_DETACH 2 /* Detach in progress */ + + +#ifdef ATM_KERNEL +/* + * SigPVC Virtual Channel Connection control block. All information regarding + * the state of a SigPVC controlled VCC will be recorded here. There will be + * one SigPVC VCC control block for each SigPVC-controlled VCC. + */ +struct sigpvc_vccb { + struct vccb vcp_hdr; /* Generic vccb */ +}; +#endif /* ATM_KERNEL */ + +/* + * SigPVC VCC Signalling Protocol States + */ +#define VCCS_NULL 0 /* No state */ +#define VCCS_ACTIVE 1 /* Active */ +#define VCCS_FREE 2 /* Waiting for user to free resources */ + + +#ifdef ATM_KERNEL +/* + * Global function declarations + */ + /* sigpvc_if.c */ + + /* sigpvc_subr.c */ +int sigpvc_create_pvc __P((struct sigpvc *, Atm_connvc *, int *)); +void sigpvc_close_vcc __P((struct vccb *)); + +#endif /* ATM_KERNEL */ + +#endif /* _SIGPVC_SIGPVC_VAR_H */ diff --git a/sys/netatm/spans/spans_arp.c b/sys/netatm/spans/spans_arp.c new file mode 100644 index 0000000..5a2443a --- /dev/null +++ b/sys/netatm/spans/spans_arp.c @@ -0,0 +1,1133 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: spans_arp.c,v 1.9 1998/06/29 22:03:12 mks Exp $ + * + */ + +/* + * SPANS Signalling Manager + * --------------------------- + * + * SPANS CLS - ARP support + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: spans_arp.c,v 1.9 1998/06/29 22:03:12 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include "spans_xdr.h" +#include <netatm/spans/spans_var.h> +#include <netatm/spans/spans_cls.h> + + +/* + * Global variables + */ +struct spansarp *spansarp_arptab[SPANSARP_HASHSIZ] = {NULL}; + + +/* + * Local functions + */ +static int spansarp_request __P((struct spansarp *)); +static void spansarp_aging __P((struct atm_time *)); +static void spansarp_retry __P((struct atm_time *)); + +/* + * Local variables + */ +static struct atm_time spansarp_timer = {0, 0}; /* Aging timer */ +static struct atm_time spansarp_rtimer = {0, 0}; /* Retry timer */ + +static struct spansarp *spansarp_retry_head = NULL; /* Retry chain */ + +static struct sp_info spansarp_pool = { + "spans arp pool", /* si_name */ + sizeof(struct spansarp), /* si_blksiz */ + 10, /* si_blkcnt */ + 100 /* si_maxallow */ +}; + + +/* + * Process a new outgoing SVC requiring SPANS ARP support + * + * This function is called by an endpoint wishing to resolve a destination + * IP address to an ATM address in order to open an SVC to that destination. + * If a valid mapping is already in our cache, then we just tell the caller + * about it and that's that. Otherwise, we have to allocate a new arp entry + * and issue a query for the mapping. + * + * Arguments: + * ivp pointer to SVC's IPVCC control block + * dst pointer to destination IP address + * + * Returns: + * MAP_VALID - Got the answer, returned via iv_arpent field. + * MAP_PROCEEDING - OK so far, querying for peer's mapping + * MAP_FAILED - error, unable to allocate resources + * + */ +int +spansarp_svcout(ivp, dst) + struct ipvcc *ivp; + struct in_addr *dst; +{ + struct spanscls *clp; + struct spansarp *sap; + int s; + + ivp->iv_arpent = NULL; + + /* + * Lookup destination address + */ + s = splnet(); + SPANSARP_LOOKUP(dst->s_addr, sap); + + if (sap) { + /* + * Link this vcc to entry queue + */ + LINK2TAIL(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext); + + /* + * If entry is valid, we're done + */ + if (sap->sa_flags & SAF_VALID) { + ivp->iv_arpent = (struct arpmap *)sap; + (void) splx(s); + return (MAP_VALID); + } + + /* + * We're already looking for this address + */ + (void) splx(s); + return (MAP_PROCEEDING); + } + + /* + * Need a new arp entry - first, find the cls instance + * corresponding to the requestor's IP interface. + */ + for (clp = spanscls_head; clp; clp = clp->cls_next) { + if (clp->cls_ipnif == ivp->iv_ipnif) + break; + } + if (clp == NULL) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Now get the new arp entry + */ + sap = (struct spansarp *)atm_allocate(&spansarp_pool); + if (sap == NULL) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Get entry set up + */ + sap->sa_dstip.s_addr = dst->s_addr; + sap->sa_dstatm.address_format = T_ATM_ABSENT; + sap->sa_dstatm.address_length = 0; + sap->sa_dstatmsub.address_format = T_ATM_ABSENT; + sap->sa_dstatmsub.address_length = 0; + sap->sa_cls = clp; + sap->sa_origin = SAO_LOOKUP; + + /* + * Link ipvcc to arp entry for later notification + */ + LINK2TAIL(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext); + + /* + * Add arp entry to table + */ + SPANSARP_ADD(sap); + + /* + * Add arp entry to retry list and start retry timer if needed + */ + LINK2TAIL(sap, struct spansarp, spansarp_retry_head, sa_rnext); + if ((spansarp_rtimer.ti_flag & TIF_QUEUED) == 0) + atm_timeout(&spansarp_rtimer, SPANSARP_RETRY, spansarp_retry); + + /* + * Issue arp request for this address + */ + (void) spansarp_request(sap); + + (void) splx(s); + return (MAP_PROCEEDING); +} + + +/* + * Process a new incoming SVC requiring SPANS ARP support + * + * This function is called by an endpoint wishing to resolve a destination + * ATM address to its IP address for an incoming call in order to allow a + * bi-directional flow of IP packets on the SVC. + * + * SPANS ARP does not provide reverse mapping facilities and only supports + * uni-directional SVCs. Thus, we lie a little to IP and always return a + * MAP_PROCEEDING indication, but we will never later notify IP of a + * MAP_VALID condition. + * + * Arguments: + * ivp pointer to SVC's IPVCC control block + * dst pointer to destination ATM address + * dstsub pointer to destination ATM subaddress + * + * Returns: + * MAP_VALID - Got the answer, returned via iv_arpent field. + * MAP_PROCEEDING - OK so far, querying for peer's mapping + * MAP_FAILED - error, unable to allocate resources + * + */ +int +spansarp_svcin(ivp, dst, dstsub) + struct ipvcc *ivp; + Atm_addr *dst; + Atm_addr *dstsub; +{ + /* + * Clear ARP entry field + */ + ivp->iv_arpent = NULL; + + return (MAP_PROCEEDING); +} + + +/* + * SPANS ARP SVC activation notification + * + * This function is called when a previously opened SVC has successfully + * been connected. + * + * Arguments: + * ivp pointer to SVC's IPVCC control block + * + * Returns: + * 0 activation processing successful + * errno activation failed - reason indicated + * + */ +int +spansarp_svcactive(ivp) + struct ipvcc *ivp; +{ + struct spansarp *sap; + int s = splnet(); + + /* + * Find an entry for the destination address + */ + SPANSARP_LOOKUP(ivp->iv_dst.s_addr, sap); + if (sap) { + /* + * IP is finished with entry, so remove IP VCC from chain + */ + UNLINK(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext); + ivp->iv_arpent = NULL; + + /* + * This seems like a reasonable reason to refresh the entry + */ + sap->sa_reftime = 0; + } + + (void) splx(s); + return (0); +} + + +/* + * SPANS ARP supported VCC is closing + * + * This function is called just prior to a user closing a VCC which + * supports SPANS ARP. We'll sever our links to the VCC and then + * figure out how much more cleanup we need to do for now. + * + * Arguments: + * ivp pointer to VCC's IPVCC control block + * + * Returns: + * none + * + */ +void +spansarp_vcclose(ivp) + struct ipvcc *ivp; +{ + struct spansarp *sap; + int s = splnet(); + + /* + * Get spansarp entry + */ + SPANSARP_LOOKUP(ivp->iv_dst.s_addr, sap); + if (sap == NULL) { + (void) splx(s); + return; + } + + /* + * Remove IP VCC from chain + */ + UNLINK(ivp, struct ipvcc, sap->sa_ivp, iv_arpnext); + ivp->iv_arpent = NULL; + + /* + * If entry is currently valid or in use, not much else for us to do + */ + if ((sap->sa_flags & (SAF_VALID | SAF_LOCKED)) || + (sap->sa_origin >= SAO_PERM)) { + (void) splx(s); + return; + } + + /* + * If there are still other VCCs waiting, exit + */ + if (sap->sa_ivp) { + (void) splx(s); + return; + } + + /* + * Noone else waiting, so remove entry from the retry chain + */ + UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext); + + /* + * Free entry + */ + SPANSARP_DELETE(sap); + atm_free((caddr_t)sap); + (void) splx(s); +} + + +/* + * Process module unloading notification + * + * Called whenever the spans module is about to be unloaded. All signalling + * instances will have been previously detached. All spansarp resources + * must be freed now. + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +spansarp_stop() +{ + int i; + + /* + * Make sure the arp table is empty + */ + for (i = 0; i < SPANSARP_HASHSIZ; i++) { + if (spansarp_arptab[i] != NULL) + panic("spansarp_stop: arp table not empty"); + } + + /* + * Cancel timers + */ + (void) atm_untimeout(&spansarp_timer); + (void) atm_untimeout(&spansarp_rtimer); + + /* + * Free our storage pools + */ + atm_release_pool(&spansarp_pool); +} + + +/* + * Process IP Network Interface Activation + * + * Called whenever an IP network interface becomes active. + * + * Called at splnet. + * + * Arguments: + * clp pointer to CLS interface + * + * Returns: + * none + * + */ +void +spansarp_ipact(clp) + struct spanscls *clp; +{ + /* + * Make sure aging timer is running + */ + if ((spansarp_timer.ti_flag & TIF_QUEUED) == 0) + atm_timeout(&spansarp_timer, SPANSARP_AGING, spansarp_aging); +} + + +/* + * Process IP Network Interface Deactivation + * + * Called whenever an IP network interface becomes inactive. + * + * Called at splnet. + * + * Arguments: + * clp pointer to CLS interface + * + * Returns: + * none + * + */ +void +spansarp_ipdact(clp) + struct spanscls *clp; +{ + struct spanscls *clp2; + struct spansarp *sap, *snext; + int i; + + /* + * Delete all interface entries + */ + for (i = 0; i < SPANSARP_HASHSIZ; i++) { + for (sap = spansarp_arptab[i]; sap; sap = snext) { + snext = sap->sa_next; + + /* + * Clean up entries for this interface + */ + if (sap->sa_cls != clp) + continue; + + /* + * All VCCs better be gone by now + */ + if (sap->sa_ivp) + panic("spansarp_ipdact: entry not empty"); + + /* + * Remove entry from the retry chain + */ + UNLINK(sap, struct spansarp, + spansarp_retry_head, sa_rnext); + + /* + * Delete entry from arp table + */ + SPANSARP_DELETE(sap); + atm_free((caddr_t)sap); + } + } + + /* + * Stop aging timer if this is the last active interface + */ + for (clp2 = spanscls_head; clp2; clp2 = clp2->cls_next) { + if ((clp != clp2) && (clp2->cls_ipnif)) + break; + } + if (clp2 == NULL) + (void) atm_untimeout(&spansarp_timer); +} + + +/* + * Issue a SPANS ARP request packet + * + * Arguments: + * sap pointer to arp table entry + * + * Returns: + * 0 packet was successfully sent + * else unable to send packet + * + */ +static int +spansarp_request(sap) + struct spansarp *sap; +{ + struct spanscls *clp; + struct spans *spp; + struct spanscls_hdr *chp; + struct spansarp_hdr *ahp; + KBuffer *m; + struct ip_nif *inp; + int err; + + clp = sap->sa_cls; + spp = clp->cls_spans; + inp = clp->cls_ipnif; + + /* + * Make sure CLS VCC is open and that we know our addresses + */ + if (clp->cls_state != CLS_OPEN) + return (1); + if (spp->sp_addr.address_format != T_ATM_SPANS_ADDR) + return (1); + if (inp == NULL) + return (1); + + /* + * Get a buffer for pdu + */ + KB_ALLOCPKT(m, ARP_PACKET_LEN, KB_F_NOWAIT, KB_T_DATA); + if (m == NULL) + return (1); + + /* + * Place pdu at end of buffer + */ + KB_PLENSET(m, ARP_PACKET_LEN); + KB_TAILALIGN(m, ARP_PACKET_LEN); + KB_DATASTART(m, chp, struct spanscls_hdr *); + ahp = (struct spansarp_hdr *)(chp + 1); + + /* + * Build headers + */ + spans_addr_copy(&spans_bcastaddr, &chp->ch_dst); + spans_addr_copy(spp->sp_addr.address, &chp->ch_src); + *(u_int *)&chp->ch_proto = *(u_int *)&spanscls_hdr.ch_proto; + *(u_int *)&chp->ch_dsap = *(u_int *)&spanscls_hdr.ch_dsap; + *(u_short *)&chp->ch_oui[1] = *(u_short *)&spanscls_hdr.ch_oui[1]; + chp->ch_pid = htons(ETHERTYPE_ARP); + + + /* + * Build ARP packet + */ + ahp->ah_hrd = htons(ARP_SPANS); + ahp->ah_pro = htons(ETHERTYPE_IP); + ahp->ah_hln = sizeof(spans_addr); + ahp->ah_pln = sizeof(struct in_addr); + ahp->ah_op = htons(ARP_REQUEST); + spans_addr_copy(spp->sp_addr.address, &ahp->ah_sha); + KM_COPY(&(IA_SIN(inp->inf_addr)->sin_addr), ahp->ah_spa, + sizeof(struct in_addr)); + KM_COPY(&sap->sa_dstip, ahp->ah_tpa, sizeof(struct in_addr)); + + /* + * Now, send the pdu via the CLS service + */ + err = atm_cm_cpcs_data(clp->cls_conn, m); + if (err) { + KB_FREEALL(m); + return (1); + } + + return (0); +} + + +/* + * Process a SPANS ARP input packet + * + * Arguments: + * clp pointer to interface CLS control block + * m pointer to input packet buffer chain + * + * Returns: + * none + * + */ +void +spansarp_input(clp, m) + struct spanscls *clp; + KBuffer *m; +{ + struct spans *spp = clp->cls_spans; + struct spanscls_hdr *chp; + struct spansarp_hdr *ahp; + struct spansarp *sap; + struct ip_nif *inp = clp->cls_ipnif; + struct in_addr in_me, in_src, in_targ; + int s, err; + + /* + * Make sure IP interface has been activated + */ + if (inp == NULL) + goto free; + + /* + * Get the packet together + */ + if (KB_LEN(m) < ARP_PACKET_LEN) { + KB_PULLUP(m, ARP_PACKET_LEN, m); + if (m == 0) + return; + } + KB_DATASTART(m, chp, struct spanscls_hdr *); + ahp = (struct spansarp_hdr *)(chp + 1); + + KM_COPY(ahp->ah_spa, &in_src, sizeof(struct in_addr)); + KM_COPY(ahp->ah_tpa, &in_targ, sizeof(struct in_addr)); + KM_COPY(&(IA_SIN(inp->inf_addr)->sin_addr), &in_me, + sizeof(struct in_addr)); + + /* + * Initial packet verification + */ + if ((ahp->ah_hrd != htons(ARP_SPANS)) || + (ahp->ah_pro != htons(ETHERTYPE_IP))) + goto free; + + /* + * Validate source addresses + * can't be from broadcast + * can't be from me + */ + if (!spans_addr_cmp(&ahp->ah_sha, &spans_bcastaddr)) + goto free; +#if (defined(BSD) && (BSD >= 199306)) + if (in_broadcast(in_src, &inp->inf_nif->nif_if)) +#else + if (in_broadcast(in_src)) +#endif + goto free; + if (!spans_addr_cmp(&ahp->ah_sha, spp->sp_addr.address)) + goto free; + if (in_src.s_addr == in_me.s_addr) { + log(LOG_ERR, + "duplicate IP address sent from spans address %s\n", + spans_addr_print(&ahp->ah_sha)); + in_targ = in_me; + goto chkop; + } + + /* + * Update arp table with source address info + */ + s = splnet(); + SPANSARP_LOOKUP(in_src.s_addr, sap); + if (sap) { + /* + * Found an entry for the source, but don't + * update permanent entries + */ + if (sap->sa_origin != SAO_PERM) { + + /* + * Update the entry + */ + sap->sa_dstatm.address_format = T_ATM_SPANS_ADDR; + sap->sa_dstatm.address_length = sizeof(spans_addr); + spans_addr_copy(&ahp->ah_sha, sap->sa_dstatm.address); + sap->sa_cls = clp; + sap->sa_reftime = 0; + if ((sap->sa_flags & SAF_VALID) == 0) { + /* + * Newly valid entry, notify waiting users + */ + struct ipvcc *ivp, *inext; + + sap->sa_flags |= SAF_VALID; + for (ivp = sap->sa_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + + ivp->iv_arpent = (struct arpmap *)sap; + (*inp->inf_arpnotify)(ivp, MAP_VALID); + } + + /* + * Remove ourselves from the retry chain + */ + UNLINK(sap, struct spansarp, + spansarp_retry_head, sa_rnext); + } + } + + } else if (in_targ.s_addr == in_me.s_addr) { + /* + * Source unknown and we're the target - add new entry + */ + sap = (struct spansarp *)atm_allocate(&spansarp_pool); + if (sap) { + sap->sa_dstip.s_addr = in_src.s_addr; + sap->sa_dstatm.address_format = T_ATM_SPANS_ADDR; + sap->sa_dstatm.address_length = sizeof(spans_addr); + spans_addr_copy(&ahp->ah_sha, sap->sa_dstatm.address); + sap->sa_dstatmsub.address_format = T_ATM_ABSENT; + sap->sa_dstatmsub.address_length = 0; + sap->sa_cls = clp; + sap->sa_flags = SAF_VALID; + sap->sa_origin = SAO_LOOKUP; + SPANSARP_ADD(sap); + } + } + (void) splx(s); + +chkop: + /* + * If this is a request for our address, send a reply + */ + if (ntohs(ahp->ah_op) != ARP_REQUEST) + goto free; + if (in_targ.s_addr != in_me.s_addr) + goto free; + + spans_addr_copy(&chp->ch_src, &chp->ch_dst); + spans_addr_copy(spp->sp_addr.address, &chp->ch_src); + ahp->ah_op = htons(ARP_REPLY); + spans_addr_copy(&ahp->ah_sha, &ahp->ah_tha); + spans_addr_copy(spp->sp_addr.address, &ahp->ah_sha); + KM_COPY(ahp->ah_spa, ahp->ah_tpa, sizeof(struct in_addr)); + KM_COPY(&in_me, ahp->ah_spa, sizeof(struct in_addr)); + + err = atm_cm_cpcs_data(clp->cls_conn, m); + if (err) + goto free; + return; + +free: + KB_FREEALL(m); +} + + +/* + * Process a SPANS ARP aging timer tick + * + * This function is called every SPANSARP_AGING seconds, in order to age + * all the arp table entries. + * + * Called at splnet. + * + * Arguments: + * tip pointer to spansarp aging timer control block + * + * Returns: + * none + * + */ +static void +spansarp_aging(tip) + struct atm_time *tip; +{ + struct spansarp *sap, *snext; + struct ipvcc *ivp, *inext; + int i; + + + /* + * Schedule next timeout + */ + atm_timeout(&spansarp_timer, SPANSARP_AGING, spansarp_aging); + + /* + * Run through arp table bumping each entry's aging timer. + */ + for (i = 0; i < SPANSARP_HASHSIZ; i++) { + for (sap = spansarp_arptab[i]; sap; sap = snext) { + snext = sap->sa_next; + + /* + * Permanent (manually installed) entries aren't aged + */ + if (sap->sa_origin == SAO_PERM) + continue; + + /* + * See if entry is valid and over-aged + */ + if ((sap->sa_flags & SAF_VALID) == 0) + continue; + if (++sap->sa_reftime < SPANSARP_MAXAGE) + continue; + + /* + * Entry is now invalid, tell IP/ATM about it + */ + sap->sa_flags |= SAF_LOCKED; + for (ivp = sap->sa_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*ivp->iv_ipnif->inf_arpnotify) + (ivp, MAP_INVALID); + } + sap->sa_flags &= ~(SAF_LOCKED | SAF_VALID); + + if (sap->sa_ivp != NULL) { + /* + * Somebody still cares, so add the arp + * entry to the retry list. + */ + LINK2TAIL(sap, struct spansarp, + spansarp_retry_head, sa_rnext); + if ((spansarp_rtimer.ti_flag & TIF_QUEUED) == 0) + atm_timeout(&spansarp_rtimer, + SPANSARP_RETRY, spansarp_retry); + + /* + * Issue arp request for this address + */ + (void) spansarp_request(sap); + + } else { + /* + * Delete unused entry + */ + SPANSARP_DELETE(sap); + atm_free((caddr_t)sap); + } + } + } +} + + +/* + * Process a SPANS ARP retry timer tick + * + * This function is called every SPANSARP_RETRY seconds, in order to retry + * awaiting arp resolution requests. We will retry requests indefinitely, + * assuming that IP will set a timeout to close the VCC(s) requesting the + * failing address resolution. + * + * Called at splnet. + * + * Arguments: + * tip pointer to spansarp retry timer control block + * + * Returns: + * none + * + */ +static void +spansarp_retry(tip) + struct atm_time *tip; +{ + struct spansarp *sap; + + + /* + * See if there's work to do + */ + if (spansarp_retry_head == NULL) { + return; + } + + /* + * Schedule next timeout + */ + atm_timeout(&spansarp_rtimer, SPANSARP_RETRY, spansarp_retry); + + /* + * Run through retry chain, (re)issuing arp requests. + */ + for (sap = spansarp_retry_head; sap; sap = sap->sa_next) { + + /* + * Send another arp request + */ + (void) spansarp_request(sap); + } +} + + +/* + * SPANS ARP IOCTL support + * + * Function will be called at splnet. + * + * Arguments: + * code PF_ATM sub-operation code + * data pointer to code specific parameter data area + * arg1 pointer to code specific argument + * + * Returns: + * 0 request procesed + * errno error processing request - reason indicated + * + */ +int +spansarp_ioctl(code, data, arg1) + int code; + caddr_t data; + caddr_t arg1; +{ + struct atmaddreq *aap; + struct atmdelreq *adp; + struct atminfreq *aip; + struct spans *spp; + struct spanscls *clp; + struct spansarp *sap; + struct air_arp_rsp aar; + struct ip_nif *inp; + struct ipvcc *ivp, *inext; + struct in_addr ip; + u_long dst; + int err = 0, i, buf_len; + caddr_t buf_addr; + + + switch (code) { + + case AIOCS_ADD_ARP: + /* + * Add a permanent ARP mapping + */ + aap = (struct atmaddreq *)data; + clp = (struct spanscls *)arg1; + inp = clp->cls_ipnif; + if ((aap->aar_arp_addr.address_format != T_ATM_SPANS_ADDR) || + (aap->aar_arp_origin != ARP_ORIG_PERM)) { + err = EINVAL; + break; + } + ip = SATOSIN(&aap->aar_arp_dst)->sin_addr; + + /* + * See if we already have an entry for this IP address + */ + SPANSARP_LOOKUP(ip.s_addr, sap); + if (sap == NULL) { + /* + * No, get a new arp entry + */ + sap = (struct spansarp *)atm_allocate(&spansarp_pool); + if (sap == NULL) { + err = ENOMEM; + break; + } + + /* + * Get entry set up + */ + sap->sa_dstip = ip; + ATM_ADDR_COPY(&aap->aar_arp_addr, &sap->sa_dstatm); + sap->sa_dstatmsub.address_format = T_ATM_ABSENT; + sap->sa_dstatmsub.address_length = 0; + sap->sa_cls = clp; + sap->sa_flags |= SAF_VALID; + sap->sa_origin = SAO_PERM; + + /* + * Add entry to table + */ + SPANSARP_ADD(sap); + break; + + } + + /* + * See if we're attempting to change the ATM address for + * this cached entry + */ + if ((sap->sa_dstatm.address_format != T_ATM_ABSENT) && + (!ATM_ADDR_EQUAL(&aap->aar_arp_addr, &sap->sa_dstatm) || + (clp != sap->sa_cls))) { + + /* + * Yes, notify IP/ATM that a mapping change has + * occurred. IP/ATM will close any VCC's which + * aren't waiting for this map. + */ + sap->sa_flags |= SAF_LOCKED; + for (ivp = sap->sa_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*inp->inf_arpnotify)(ivp, MAP_CHANGED); + } + sap->sa_flags &= ~SAF_LOCKED; + } + + /* + * Update the cached entry with the new data + */ + ATM_ADDR_COPY(&aap->aar_arp_addr, &sap->sa_dstatm); + sap->sa_cls = clp; + + /* + * If this entry isn't valid, notify anyone who might + * be interested + */ + if ((sap->sa_flags & SAF_VALID) == 0) { + + sap->sa_flags |= SAF_LOCKED; + for (ivp = sap->sa_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*inp->inf_arpnotify)(ivp, MAP_VALID); + } + sap->sa_flags &= ~SAF_LOCKED; + } + + /* + * Remove this entry from the retry chain + */ + UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext); + + /* + * Mark the entry as permanent + */ + sap->sa_flags |= SAF_VALID; + sap->sa_origin = SAO_PERM; + break; + + case AIOCS_DEL_ARP: + /* + * Delete an ARP mapping + */ + adp = (struct atmdelreq *)data; + clp = (struct spanscls *)arg1; + ip = SATOSIN(&adp->adr_arp_dst)->sin_addr; + + /* + * Now find the entry to be deleted + */ + SPANSARP_LOOKUP(ip.s_addr, sap); + if (sap == NULL) { + err = ENOENT; + break; + } + + /* + * Notify all VCCs using this entry that they must finish + * up now. + */ + sap->sa_flags |= SAF_LOCKED; + for (ivp = sap->sa_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED); + } + + /* + * Now free up the entry + */ + UNLINK(sap, struct spansarp, spansarp_retry_head, sa_rnext); + SPANSARP_DELETE(sap); + atm_free((caddr_t)sap); + break; + + case AIOCS_INF_ARP: + /* + * Get ARP table information + */ + aip = (struct atminfreq *)data; + spp = (struct spans *)arg1; + + if (aip->air_arp_addr.sa_family != AF_INET) + break; + dst = SATOSIN(&aip->air_arp_addr)->sin_addr.s_addr; + + buf_addr = aip->air_buf_addr; + buf_len = aip->air_buf_len; + + if ((clp = spp->sp_cls) == NULL) + break; + + /* + * Run through entire arp table + */ + for (i = 0; i < SPANSARP_HASHSIZ; i++) { + for (sap = spansarp_arptab[i]; sap; + sap = sap->sa_next) { + /* + * We only want entries learned + * from the supplied interface. + */ + if (sap->sa_cls != clp) + continue; + if ((dst != INADDR_ANY) && + (dst != sap->sa_dstip.s_addr)) + continue; + + /* + * Make sure there's room in the user's buffer + */ + if (buf_len < sizeof(aar)) { + err = ENOSPC; + break; + } + + /* + * Fill in info to be returned + */ + SATOSIN(&aar.aap_arp_addr)->sin_family = + AF_INET; + SATOSIN(&aar.aap_arp_addr)->sin_addr.s_addr = + sap->sa_dstip.s_addr; + (void) sprintf(aar.aap_intf, "%s%d", + clp->cls_ipnif->inf_nif->nif_if.if_name, + clp->cls_ipnif->inf_nif->nif_if.if_unit + ); + aar.aap_flags = sap->sa_flags; + aar.aap_origin = sap->sa_origin; + if (sap->sa_flags & SAF_VALID) + aar.aap_age = SPANSARP_MAXAGE - + sap->sa_reftime; + else + aar.aap_age = 0; + ATM_ADDR_COPY(&sap->sa_dstatm, &aar.aap_addr); + ATM_ADDR_COPY(&sap->sa_dstatmsub, + &aar.aap_subaddr); + + /* + * Copy the response into the user's buffer + */ + if (err = copyout((caddr_t)&aar, buf_addr, + sizeof(aar))) + break; + buf_addr += sizeof(aar); + buf_len -= sizeof(aar); + } + if (err) + break; + } + + /* + * Update the buffer pointer and length + */ + aip->air_buf_addr = buf_addr; + aip->air_buf_len = buf_len; + break; + + default: + err = EOPNOTSUPP; + } + + return (err); +} + diff --git a/sys/netatm/spans/spans_cls.c b/sys/netatm/spans/spans_cls.c new file mode 100644 index 0000000..f496311 --- /dev/null +++ b/sys/netatm/spans/spans_cls.c @@ -0,0 +1,848 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: spans_cls.c,v 1.11 1998/06/29 22:04:29 mks Exp $ + * + */ + +/* + * SPANS Signalling Manager + * --------------------------- + * + * SPANS Connectionless Datagram Service (CLS) module + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: spans_cls.c,v 1.11 1998/06/29 22:04:29 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include "spans_xdr.h" +#include <netatm/spans/spans_var.h> +#include <netatm/spans/spans_cls.h> + + +/* + * Global variables + */ +int spanscls_print = 0; + +struct spanscls *spanscls_head = NULL; + +struct spans_addr spans_bcastaddr = { + { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } +}; + +struct spanscls_hdr spanscls_hdr = { + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* dst */ + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, /* src */ + 0x00, 0x00, 0, + 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0 /* LLC SNAP */ +}; + + +/* + * Local functions + */ +static int spanscls_ipact __P((struct ip_nif *)); +static int spanscls_ipdact __P((struct ip_nif *)); +static int spanscls_bcast_output __P((struct ip_nif *, KBuffer *)); +static void spanscls_cpcs_data __P((void *, KBuffer *)); +static void spanscls_connected __P((void *)); +static void spanscls_cleared __P((void *, struct t_atm_cause *)); +static caddr_t spanscls_getname __P((void *)); +static void spanscls_pdu_print __P((struct spanscls *, KBuffer *, + char *)); + +/* + * Local variables + */ +static struct sp_info spanscls_pool = { + "spans cls pool", /* si_name */ + sizeof(struct spanscls), /* si_blksiz */ + 2, /* si_blkcnt */ + 100 /* si_maxallow */ +}; + +static struct ip_serv spanscls_ipserv = { + spanscls_ipact, + spanscls_ipdact, + spansarp_ioctl, + NULL, + spansarp_svcout, + spansarp_svcin, + spansarp_svcactive, + spansarp_vcclose, + spanscls_bcast_output, + { + {ATM_AAL5, ATM_ENC_NULL}, + {ATM_AAL3_4, ATM_ENC_NULL} + } +}; + +static u_char spanscls_bridged[] = { + 0x00, 0x00, 0x00, 0x00, + 0xaa, 0xaa, 0x03, 0x00, 0x80, 0xc2 /* LLC SNAP */ +}; + +static Atm_endpoint spanscls_endpt = { + NULL, + ENDPT_SPANS_CLS, + NULL, + spanscls_getname, + spanscls_connected, + spanscls_cleared, + NULL, + NULL, + NULL, + NULL, + spanscls_cpcs_data, + NULL, + NULL, + NULL, + NULL +}; + +static Atm_attributes spanscls_attr = { + NULL, /* nif */ + CMAPI_CPCS, /* api */ + 0, /* api_init */ + 0, /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, + ATM_AAL3_4 + }, + { /* traffic */ + T_ATM_PRESENT, + { + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + { + T_ATM_ABSENT, + 0, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_NO + }, + T_YES + }, + }, + { /* bearer */ + T_ATM_PRESENT, + { + T_ATM_CLASS_X, + T_ATM_NULL, + T_ATM_NULL, + T_NO, + T_ATM_1_TO_1 + } + }, + { /* bhli */ + T_ATM_ABSENT + }, + { /* blli */ + T_ATM_ABSENT, + T_ATM_ABSENT + }, + { /* llc */ + T_ATM_ABSENT + }, + { /* called */ + T_ATM_PRESENT, + }, + { /* calling */ + T_ATM_ABSENT + }, + { /* qos */ + T_ATM_PRESENT, + { + T_ATM_NETWORK_CODING, + { + T_ATM_QOS_CLASS_0, + }, + { + T_ATM_QOS_CLASS_0 + } + } + }, + { /* transit */ + T_ATM_ABSENT + }, + { /* cause */ + T_ATM_ABSENT + } +}; + +static struct t_atm_cause spanscls_cause = { + T_ATM_ITU_CODING, + T_ATM_LOC_USER, + T_ATM_CAUSE_UNSPECIFIED_NORMAL, + {0, 0, 0, 0} +}; + + +/* + * Process module loading + * + * Called whenever the spans module is initializing. + * + * Arguments: + * none + * + * Returns: + * 0 initialization successful + * errno initialization failed - reason indicated + * + */ +int +spanscls_start() +{ + int err; + + /* + * Fill in union fields + */ + spanscls_attr.aal.v.aal4.forward_max_SDU_size = ATM_NIF_MTU; + spanscls_attr.aal.v.aal4.backward_max_SDU_size = ATM_NIF_MTU; + spanscls_attr.aal.v.aal4.SSCS_type = T_ATM_NULL; + spanscls_attr.aal.v.aal4.mid_low = 0; + spanscls_attr.aal.v.aal4.mid_high = 1023; + + /* + * Register our endpoint + */ + err = atm_endpoint_register(&spanscls_endpt); + + return (err); +} + + +/* + * Process module unloading notification + * + * Called whenever the spans module is about to be unloaded. All signalling + * instances will have been previously detached. All spanscls resources + * must be freed now. + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +spanscls_stop() +{ + int s = splnet(); + + /* + * Tell ARP to stop + */ + spansarp_stop(); + + /* + * Nothing should be left here... + */ + if (spanscls_head) { + panic("spanscls_stop: bad state"); + } + (void) splx(s); + + /* + * De-register ourselves + */ + (void) atm_endpoint_deregister(&spanscls_endpt); + + /* + * Free our storage pools + */ + atm_release_pool(&spanscls_pool); +} + + +/* + * Process signalling interface attach + * + * This function is called whenever a physical interface has been attached + * to spans. We will open the CLS PVC and await further events. + * + * Called at splnet. + * + * Arguments: + * spp pointer to spans signalling protocol instance + * + * Returns: + * 0 attach successful + * errno attach failed - reason indicated + * + */ +int +spanscls_attach(spp) + struct spans *spp; +{ + struct spanscls *clp; + Atm_addr_pvc *pvcp; + int err; + + /* + * Get a new cls control block + */ + clp = (struct spanscls *)atm_allocate(&spanscls_pool); + if (clp == NULL) + return (ENOMEM); + + /* + * Initialize some stuff + */ + clp->cls_state = CLS_CLOSED; + clp->cls_spans = spp; + spp->sp_ipserv = &spanscls_ipserv; + + /* + * Fill out connection attributes + */ + spanscls_attr.nif = spp->sp_pif->pif_nif; + spanscls_attr.traffic.v.forward.PCR_all_traffic = spp->sp_pif->pif_pcr; + spanscls_attr.traffic.v.backward.PCR_all_traffic = spp->sp_pif->pif_pcr; + spanscls_attr.called.addr.address_format = T_ATM_PVC_ADDR; + spanscls_attr.called.addr.address_length = sizeof(Atm_addr_pvc); + pvcp = (Atm_addr_pvc *)spanscls_attr.called.addr.address; + ATM_PVC_SET_VPI(pvcp, SPANS_CLS_VPI); + ATM_PVC_SET_VCI(pvcp, SPANS_CLS_VCI); + spanscls_attr.called.subaddr.address_format = T_ATM_ABSENT; + spanscls_attr.called.subaddr.address_length = 0; + + /* + * Create SPANS Connectionless Service (CLS) PVC + */ + err = atm_cm_connect(&spanscls_endpt, clp, &spanscls_attr, + &clp->cls_conn); + if (err) { + atm_free((caddr_t)clp); + return (err); + } + + /* + * Set new state and link instance + */ + clp->cls_state = CLS_OPEN; + LINK2TAIL(clp, struct spanscls, spanscls_head, cls_next); + spp->sp_cls = clp; + + return (0); +} + + +/* + * Process signalling interface detach + * + * This function is called whenever a physical interface has been detached + * from spans. We will close the CLS PVC and clean up everything. + * + * Called at splnet. + * + * Arguments: + * spp pointer to spans signalling protocol instance + * + * Returns: + * none + * + */ +void +spanscls_detach(spp) + struct spans *spp; +{ + struct spanscls *clp; + + /* + * Get our control block + */ + clp = spp->sp_cls; + if (clp == NULL) + return; + + /* + * Just checking up on things... + */ + if (clp->cls_ipnif) + panic("spanscls_detach: IP interface still active"); + + /* + * Close CLS PVC + */ + spanscls_closevc(clp, &spanscls_cause); + + /* + * Sever links and free server block, if possible + */ + clp->cls_spans = NULL; + spp->sp_cls = NULL; + if (clp->cls_state == CLS_CLOSED) { + UNLINK(clp, struct spanscls, spanscls_head, cls_next); + atm_free((caddr_t)clp); + } +} + + +/* + * Process IP Network Interface Activation + * + * Called whenever an IP network interface becomes active. + * + * Called at splnet. + * + * Arguments: + * inp pointer to IP network interface + * + * Returns: + * 0 command successful + * errno command failed - reason indicated + * + */ +static int +spanscls_ipact(inp) + struct ip_nif *inp; +{ + struct spans *spp; + struct spanscls *clp; + + /* + * Get corresponding cls instance + */ + spp = (struct spans *)inp->inf_nif->nif_pif->pif_siginst; + if ((spp == NULL) || ((clp = spp->sp_cls) == NULL)) + return (ENXIO); + + /* + * Make sure it's not already activated + */ + if (clp->cls_ipnif) + return (EEXIST); + + /* + * Set two-way links with IP world + */ + clp->cls_ipnif = inp; + inp->inf_isintf = (caddr_t)clp; + + /* + * Tell arp about new interface + */ + spansarp_ipact(clp); + + return (0); +} + + +/* + * Process IP Network Interface Deactivation + * + * Called whenever an IP network interface becomes inactive. + * + * Called at splnet. + * + * Arguments: + * inp pointer to IP network interface + * + * Returns: + * 0 command successful + * errno command failed - reason indicated + * + */ +static int +spanscls_ipdact(inp) + struct ip_nif *inp; +{ + struct spanscls *clp; + + /* + * Get cls instance and make sure it's been activated + */ + clp = (struct spanscls *)inp->inf_isintf; + if ((clp == NULL) || (clp->cls_ipnif == NULL)) + return (ENXIO); + + /* + * Let arp know about this + */ + spansarp_ipdact(clp); + + /* + * Clear IP interface pointer + */ + clp->cls_ipnif = NULL; + return (0); +} + + +/* + * Output IP Broadcast Packet + * + * Called whenever an IP broadcast packet is sent to this interface. + * + * Arguments: + * inp pointer to IP network interface + * m pointer to packet buffer chain + * + * Returns: + * 0 packet sent successfully + * errno send failed - reason indicated + * + */ +static int +spanscls_bcast_output(inp, m) + struct ip_nif *inp; + KBuffer *m; +{ + struct spans *spp; + struct spanscls *clp; + struct spanscls_hdr *chp; + int err, space; + + /* + * Get cls instance and make sure it's been activated + */ + clp = (struct spanscls *)inp->inf_isintf; + if ((clp == NULL) || (clp->cls_ipnif == NULL)) { + KB_FREEALL(m); + return (ENETDOWN); + } + + /* + * Make sure that we know our addresses + */ + spp = clp->cls_spans; + if (spp->sp_addr.address_format != T_ATM_SPANS_ADDR) { + KB_FREEALL(m); + return (ENETDOWN); + } + + /* + * See if there's room to add CLS header to front of packet. + */ + KB_HEADROOM(m, space); + if (space < sizeof(struct spanscls_hdr)) { + KBuffer *n; + + /* + * We have to allocate another buffer and tack it + * onto the front of the packet + */ + KB_ALLOCPKT(n, sizeof(struct spanscls_hdr), + KB_F_NOWAIT, KB_T_HEADER); + if (n == 0) { + KB_FREEALL(m); + return (ENOBUFS); + } + KB_TAILALIGN(n, sizeof(struct spanscls_hdr)); + KB_LINKHEAD(n, m); + m = n; + } else { + /* + * Header fits, just adjust buffer controls + */ + KB_HEADADJ(m, sizeof(struct spanscls_hdr)); + } + + /* + * Now, build the CLS header + */ + KB_DATASTART(m, chp, struct spanscls_hdr *); + spans_addr_copy(&spans_bcastaddr, &chp->ch_dst); + spans_addr_copy(spp->sp_addr.address, &chp->ch_src); + *(u_int *)&chp->ch_proto = *(u_int *)&spanscls_hdr.ch_proto; + *(u_int *)&chp->ch_dsap = *(u_int *)&spanscls_hdr.ch_dsap; + *(u_short *)&chp->ch_oui[1] = *(u_short *)&spanscls_hdr.ch_oui[1]; + chp->ch_pid = htons(ETHERTYPE_IP); + +#ifdef DIAGNOSTIC + if (spanscls_print) + spanscls_pdu_print(clp, m, "output"); +#endif + + /* + * Finally, send the pdu via the CLS service + */ + err = atm_cm_cpcs_data(clp->cls_conn, m); + if (err) { + KB_FREEALL(m); + return (ENOBUFS); + } + + return (0); +} + + +/* + * Process VCC Input Data + * + * All input packets received from CLS VCC lower layers are processed here. + * + * Arguments: + * tok connection token (pointer to CLS VCC control block) + * m pointer to input packet buffer chain + * + * Returns: + * none + * + */ +static void +spanscls_cpcs_data(tok, m) + void *tok; + KBuffer *m; +{ + struct spanscls *clp = tok; + struct spans *spp = clp->cls_spans; + struct spanscls_hdr *chp; + struct ip_nif *inp; + + /* + * Make sure we're ready + */ + if ((clp->cls_state != CLS_OPEN) || (spp->sp_state != SPANS_ACTIVE)) { + KB_FREEALL(m); + return; + } + +#ifdef DIAGNOSTIC + if (spanscls_print) + spanscls_pdu_print(clp, m, "input"); +#endif + + /* + * Get CLS header into buffer + */ + if (KB_LEN(m) < sizeof(struct spanscls_hdr)) { + KB_PULLUP(m, sizeof(struct spanscls_hdr), m); + if (m == 0) + return; + } + KB_DATASTART(m, chp, struct spanscls_hdr *); + + /* + * Verify packet information + */ + if ((*(u_int *)&chp->ch_proto != *(u_int *)&spanscls_hdr.ch_proto) || + (*(u_int *)&chp->ch_dsap != *(u_int *)&spanscls_hdr.ch_dsap) || + (*(u_short *)&chp->ch_oui[1] != + *(u_short *)&spanscls_hdr.ch_oui[1])) { + + /* + * Check for bridged PDU + */ + if (bcmp((char *)&chp->ch_proto, (char *)spanscls_bridged, + sizeof(spanscls_bridged))) { + log(LOG_ERR, "spanscls_input: bad format\n"); +#ifdef DIAGNOSTIC + spanscls_pdu_print(clp, m, "input error"); +#endif + } + + KB_FREEALL(m); + return; + } + + /* + * Make sure packet is for us + */ + if (spans_addr_cmp(&chp->ch_dst, spp->sp_addr.address) && + spans_addr_cmp(&chp->ch_dst, &spans_bcastaddr)) { + KB_FREEALL(m); + return; + } + + /* + * Do protocol processing + */ + switch (ntohs(chp->ch_pid)) { + + case ETHERTYPE_IP: + /* + * Drop CLS header + */ + KB_HEADADJ(m, -sizeof(struct spanscls_hdr)); + KB_PLENADJ(m, -sizeof(struct spanscls_hdr)); + + /* + * Packet is ready for input to IP + */ + if (inp = clp->cls_ipnif) + (void) (*inp->inf_ipinput)(inp, m); + else + KB_FREEALL(m); + break; + + case ETHERTYPE_ARP: + spansarp_input(clp, m); + break; + + default: + log(LOG_ERR, "spanscls_input: unknown protocol 0x%x\n", + chp->ch_pid); + KB_FREEALL(m); + return; + } +} + + +/* + * Close a SPANS CLS VCC + * + * This function will close a SPANS CLS VCC. + * + * Arguments: + * clp pointer to CLS instance + * cause pointer to cause code + * + * Returns: + * none + * + */ +void +spanscls_closevc(clp, cause) + struct spanscls *clp; + struct t_atm_cause *cause; +{ + int err; + + /* + * Close VCC + */ + if (clp->cls_conn) { + err = atm_cm_release(clp->cls_conn, cause); + if (err) { + log(LOG_ERR, "spanscls_closevc: release err=%d\n", err); + } + clp->cls_conn = NULL; + } + + clp->cls_state = CLS_CLOSED; +} + + +/* + * Process CLS VCC Connected Notification + * + * Arguments: + * toku user's connection token (spanscls protocol block) + * + * Returns: + * none + * + */ +static void +spanscls_connected(toku) + void *toku; +{ + /* + * We should never get one of these + */ + log(LOG_ERR, "spanscls: unexpected connected event\n"); +} + + +/* + * Process CLS VCC Cleared Notification + * + * Arguments: + * toku user's connection token (spanscls protocol block) + * cause pointer to cause code + * + * Returns: + * none + * + */ +static void +spanscls_cleared(toku, cause) + void *toku; + struct t_atm_cause *cause; +{ + struct spanscls *clp = (struct spanscls *)toku; + + /* + * CLS VCC has been closed, so clean up our side + */ + clp->cls_conn = NULL; + spanscls_closevc(clp, cause); +} + + +/* + * Get Connection's Application/Owner Name + * + * Arguments: + * tok spanscls connection token + * + * Returns: + * addr pointer to string containing our name + * + */ +static caddr_t +spanscls_getname(tok) + void *tok; +{ + return ("SPANSCLS"); +} + + +/* + * Print a SPANS CLS PDU + * + * Arguments: + * clp pointer to cls instance + * m pointer to pdu buffer chain + * msg pointer to message string + * + * Returns: + * none + * + */ +static void +spanscls_pdu_print(clp, m, msg) + struct spanscls *clp; + KBuffer *m; + char *msg; +{ + char buf[128]; + + sprintf(buf, "spanscls %s:\n", msg); + atm_pdu_print(m, buf); +} + diff --git a/sys/netatm/spans/spans_cls.h b/sys/netatm/spans/spans_cls.h new file mode 100644 index 0000000..d2cacac --- /dev/null +++ b/sys/netatm/spans/spans_cls.h @@ -0,0 +1,188 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: spans_cls.h,v 1.6 1998/05/18 19:11:17 mks Exp $ + * + */ + +/* + * SPANS Signalling Manager + * --------------------------- + * + * SPANS Connectionless Datagram Service (CLS) control blocks + * + */ + +#ifndef _SPANS_SPANSCLS_H +#define _SPANS_SPANSCLS_H + +/* + * Protocol constants + */ +#define SPANSARP_AGING (60 * ATM_HZ) /* ARP aging timer */ +#define SPANSARP_RETRY (3 * ATM_HZ) /* ARP retry timer */ +#define SPANSARP_MAXAGE 20 /* Max ARP entry age (minutes)*/ +#define SPANSARP_HASHSIZ 19 /* Hash table size */ + + +/* + * SPANS CLS protocol structure. There will be one such structure for + * each SPANS signalling instance. + */ +struct spanscls { + struct spanscls *cls_next; /* Next attached cls instance */ + u_char cls_state; /* Protocol state (see below) */ + struct spans *cls_spans; /* Spans signalling instance */ + Atm_connection *cls_conn; /* Connection manager token */ + struct ip_nif *cls_ipnif; /* IP network interface */ +}; + +/* + * SPANS CLS Protocol States + */ +#define CLS_CLOSED 1 /* CLS PVC is closed */ +#define CLS_OPEN 2 /* CLS PVC is open */ + + +/* + * Structure for SPANS ARP mappings. Each of these structures will contain + * IP address to SPANS hardware address mappings. There will be one such + * structure for each IP address currently in use. + */ +struct spansarp { + struct arpmap sa_arpmap; /* Common entry header */ + struct spanscls *sa_cls; /* Interface where we learned answer */ + struct spansarp *sa_next; /* Hash chain */ + struct spansarp *sa_rnext; /* Retry chain */ + u_char sa_flags; /* Flags (see below) */ + u_char sa_origin; /* Origin (see below) */ + u_short sa_reftime; /* Entry reference time (minutes) */ + struct ipvcc *sa_ivp; /* IP VCCs waiting for answer */ +}; +#define sa_dstip sa_arpmap.am_dstip +#define sa_dstatm sa_arpmap.am_dstatm +#define sa_dstatmsub sa_arpmap.am_dstatmsub + +/* + * Entry Flags + */ +#define SAF_VALID ARPF_VALID /* Entry is valid */ +#define SAF_REFRESH ARPF_REFRESH /* Entry has been refreshed */ +#define SAF_LOCKED 0x04 /* Entry is locked */ + +/* + * Entry Origin + */ +#define SAO_PERM ARP_ORIG_PERM /* Entry is permanently installed */ +#define SAO_LOOKUP 20 /* Learned via lookup */ + + +/* + * SPANS CLS Packet Header + */ +struct spanscls_hdr { + /* IEEE 802.6 MAC header */ + spans_addr ch_dst; /* Destination SPANS address */ + spans_addr ch_src; /* Source SPANS address */ + u_char ch_proto; /* */ + u_char ch_extlen; /* */ + u_short ch_bridging; /* */ + + /* LLC SNAP header */ + u_char ch_dsap; /* Destination SAP */ + u_char ch_ssap; /* Source SAP */ + u_char ch_ctl; /* Control field */ + u_char ch_oui[3]; /* Organizationally Unique Identifier */ + u_short ch_pid; /* Protocol Identifier */ +}; + +/* + * SPANS ARP Packet Format + */ +struct spansarp_hdr { + u_short ah_hrd; /* Hardware type (see below) */ + u_short ah_pro; /* Protocol type */ + u_char ah_hln; /* Length of hardware address */ + u_char ah_pln; /* Length of protocol address */ + u_short ah_op; /* Operation code (see below) */ + spans_addr ah_sha; /* Source hardware address */ + u_char ah_spa[4]; /* Source protocol address */ + spans_addr ah_tha; /* Target hardware address */ + u_char ah_tpa[4]; /* Target protocol address */ +}; + +/* + * Hardware types + */ +#define ARP_SPANS 0x4040 + +/* + * Operation types + */ +#define ARP_REQUEST 1 /* SPANSARP request */ +#define ARP_REPLY 2 /* SPANSARP response */ + +#define ARP_PACKET_LEN \ + (sizeof(struct spanscls_hdr) + sizeof(struct spansarp_hdr)) + +#ifdef ATM_KERNEL +/* + * Macros for manipulating SPANS ARP tables and entries + */ +#define SPANSARP_HASH(ip) ((u_long)(ip) % SPANSARP_HASHSIZ) + +#define SPANSARP_ADD(sa) \ +{ \ + struct spansarp **h; \ + h = &spansarp_arptab[SPANSARP_HASH((sa)->sa_dstip.s_addr)]; \ + LINK2TAIL((sa), struct spansarp, *h, sa_next); \ +} + +#define SPANSARP_DELETE(sa) \ +{ \ + struct spansarp **h; \ + h = &spansarp_arptab[SPANSARP_HASH((sa)->sa_dstip.s_addr)]; \ + UNLINK((sa), struct spansarp, *h, sa_next); \ +} + +#define SPANSARP_LOOKUP(ip, sa) \ +{ \ + for ((sa) = spansarp_arptab[SPANSARP_HASH(ip)]; \ + (sa); (sa) = (sa)->sa_next) { \ + if ((sa)->sa_dstip.s_addr == (ip)) \ + break; \ + } \ +} + + +/* + * External variables + */ +extern struct spanscls *spanscls_head; +extern struct spanscls_hdr spanscls_hdr; + +#endif /* ATM_KERNEL */ + +#endif /* _SPANS_SPANSCLS_H */ diff --git a/sys/netatm/spans/spans_if.c b/sys/netatm/spans/spans_if.c new file mode 100644 index 0000000..4facf73 --- /dev/null +++ b/sys/netatm/spans/spans_if.c @@ -0,0 +1,1336 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: spans_if.c,v 1.12 1998/08/26 23:29:09 mks Exp $ + * + */ + +/* + * SPANS Signalling Manager + * --------------------------- + * + * External interfaces to SPANS manager. Includes support for + * running as a loadable kernel module. + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: spans_if.c,v 1.12 1998/08/26 23:29:09 mks Exp $"; +#endif + +#ifndef ATM_SPANS_MODULE +#include "opt_atm.h" +#endif + +#include <netatm/kern_include.h> + +#include "spans_xdr.h" +#include <netatm/spans/spans_var.h> + +/* + * Global variables + */ +struct sp_info spans_vcpool = { + "spans vcc pool", /* si_name */ + sizeof(struct spans_vccb), /* si_blksiz */ + 10, /* si_blkcnt */ + 50 /* si_maxallow */ +}; + +struct sp_info spans_msgpool = { + "spans message pool", /* si_name */ + sizeof(spans_msg), /* si_blksiz */ + 10, /* si_blkcnt */ + 50 /* si_maxallow */ +}; + +/* + * Local functions + */ +static int spans_start __P((void)); +static int spans_stop __P((void)); +static int spans_attach __P((struct sigmgr *, struct atm_pif *)); +static int spans_detach __P((struct atm_pif *)); +static int spans_setup __P((Atm_connvc *, int *)); +static int spans_release __P((struct vccb *, int *)); +static int spans_accept __P((struct vccb *, int *)); +static int spans_reject __P((struct vccb *, int *)); +static int spans_ioctl __P((int, caddr_t, caddr_t)); + +/* + * Local variables + */ +static struct sigmgr *spans_mgr = NULL; + + +/* + * Initialize SPANS processing + * + * This will be called during module loading. We'll just register + * the SPANS protocol descriptor and wait for a SPANS ATM interface + * to come online. + * + * Arguments: + * none + * + * Returns: + * 0 startup was successful + * errno startup failed - reason indicated + * + */ +static int +spans_start() +{ + int err = 0; + + /* + * Verify software version + */ + if (atm_version != ATM_VERSION) { + log(LOG_ERR, "version mismatch: spans=%d.%d kernel=%d.%d\n", + ATM_VERS_MAJ(ATM_VERSION), + ATM_VERS_MIN(ATM_VERSION), + ATM_VERS_MAJ(atm_version), + ATM_VERS_MIN(atm_version)); + return (EINVAL); + } + + /* + * Allocate protocol definition structure + */ + spans_mgr = (struct sigmgr *)KM_ALLOC(sizeof(struct sigmgr), + M_DEVBUF, M_NOWAIT); + if (spans_mgr == NULL) { + err = ENOMEM; + goto done; + } + KM_ZERO(spans_mgr, sizeof(struct sigmgr)); + + /* + * Initialize protocol invariant values + */ + spans_mgr->sm_proto = ATM_SIG_SPANS; + spans_mgr->sm_attach = spans_attach; + spans_mgr->sm_detach = spans_detach; + spans_mgr->sm_setup = spans_setup; + spans_mgr->sm_release = spans_release; + spans_mgr->sm_accept = spans_accept; + spans_mgr->sm_reject = spans_reject; + spans_mgr->sm_free = spans_free; + spans_mgr->sm_ioctl = spans_ioctl; + + /* + * Register ourselves with system + */ + err = atm_sigmgr_register(spans_mgr); + if (err) + goto done; + + /* + * Start up Connectionless Service + */ + err = spanscls_start(); + if (err) + goto done; + +done: + return (err); +} + + +/* + * Halt SPANS processing + * + * This should be called just prior to unloading the module from + * memory. All SPANS interfaces must be deregistered before the + * protocol can be shutdown. + * + * Arguments: + * none + * + * Returns: + * 0 startup was successful + * errno startup failed - reason indicated + * + */ +static int +spans_stop() +{ + int err = 0; + int s = splnet(); + + /* + * Is protocol even set up? + */ + if (spans_mgr) { + + /* + * Any protocol instances still registered? + */ + if (spans_mgr->sm_prinst) { + + /* Yes, can't stop now */ + err = EBUSY; + goto done; + } + + /* + * Stop Connectionless Service + */ + spanscls_stop(); + + /* + * De-register from system + */ + err = atm_sigmgr_deregister(spans_mgr); + + /* + * Free up protocol block + */ + KM_FREE(spans_mgr, sizeof(struct sigmgr), M_DEVBUF); + spans_mgr = NULL; + + /* + * Free up our storage pools + */ + atm_release_pool(&spans_vcpool); + atm_release_pool(&spans_msgpool); + } else + err = ENXIO; + +done: + (void) splx(s); + return (err); +} + + +/* + * Attach a SPANS-controlled interface + * + * Each ATM physical interface must be attached with the signalling + * manager for the interface's signalling protocol (via the + * atm_sigmgr_attach function). This function will handle the + * attachment for SPANS-controlled interfaces. A new SPANS protocol + * instance will be created and then we'll just sit around waiting for + * status or connection requests. + * + * Function must be called at splnet. + * + * Arguments: + * smp pointer to SPANS signalling manager control block + * pip pointer to ATM physical interface control block + * + * Returns: + * 0 attach successful + * errno attach failed - reason indicated + * + */ +static int +spans_attach(smp, pip) + struct sigmgr *smp; + struct atm_pif *pip; +{ + int err = 0, n = 0, s; + struct spans *spp = NULL; + struct atm_nif *np; + + ATM_DEBUG2("spans_attach: smp=%x, pip=%x\n", smp, pip); + + /* + * Count network interfaces attached to the physical interface. + * If there are more or less than one, we have big problems. + */ + np = pip->pif_nif; + while (np) { + n++; + np = np->nif_pnext; + } + if (n != 1) { + err = ETOOMANYREFS; + goto done; + } + + /* + * Allocate SPANS protocol instance control block + */ + spp = (struct spans *)KM_ALLOC(sizeof(struct spans), + M_DEVBUF, M_NOWAIT); + if (spp == NULL) { + err = ENOMEM; + goto done; + } + KM_ZERO(spp, sizeof(struct spans)); + + /* + * Set variables in SPANS protocol instance control block + */ + spp->sp_state = SPANS_INIT; + spp->sp_h_epoch = time_second; + spp->sp_s_epoch = 0; + spp->sp_addr.address_format = T_ATM_ABSENT; + spp->sp_addr.address_length = 0; + spp->sp_subaddr.address_format = T_ATM_ABSENT; + spp->sp_subaddr.address_length = 0; + spp->sp_probe_ct = 0; + spp->sp_alloc_vci = SPANS_MIN_VCI; + spp->sp_alloc_vpi = SPANS_VPI; + spp->sp_min_vci = SPANS_MIN_VCI; + spp->sp_max_vci = pip->pif_maxvci; + + /* + * Link instance into manager's chain + */ + LINK2TAIL((struct siginst *)spp, struct siginst, smp->sm_prinst, + si_next); + + /* + * Link in interface + */ + spp->sp_pif = pip; + pip->pif_sigmgr = smp; + pip->pif_siginst = (struct siginst *) spp; + + /* + * Kick-start the SPANS protocol + */ + SPANS_TIMER(spp, 0); + + /* + * Notify Connectionless Service + */ + err = spanscls_attach(spp); + + /* + * Log the fact that we've attached + */ + if (!err) + log(LOG_INFO, "spans: attached to interface %s%d\n", + pip->pif_name, pip->pif_unit); + +done: + /* + * Reset our work if attach fails + */ + if (err) { + if (spp) { + SPANS_CANCEL(spp); + UNLINK((struct siginst *)spp, struct siginst, + smp->sm_prinst, si_next); + KM_FREE(spp, sizeof(struct spans), M_DEVBUF); + } + s = splimp(); + pip->pif_sigmgr = NULL; + pip->pif_siginst = NULL; + (void) splx(s); + } + + return (err); +} + + +/* + * Detach a SPANS-controlled interface + * + * Each ATM physical interface may be detached from its signalling + * manager (via the atm_sigmgr_detach function). This function will + * handle the detachment for all SPANS-controlled interfaces. All + * circuits will be immediately terminated. + * + * Function must be called at splnet. + * + * Arguments: + * pip pointer to ATM physical interface control block + * + * Returns: + * 0 detach successful + * errno detach failed - reason indicated + * + */ +static int +spans_detach(pip) + struct atm_pif *pip; +{ + struct spans *spp; + struct vccb *vcp, *vnext; + Atm_connection *cop; + int err; + + ATM_DEBUG1("spans_detach: pip=0x%x\n", pip); + + /* + * Get SPANS protocol instance + */ + spp = (struct spans *)pip->pif_siginst; + + /* + * Return an error if we're already detaching + */ + if (spp->sp_state == SPANS_DETACH) { + return(EALREADY); + } + + /* + * Cancel any outstanding timer + */ + SPANS_CANCEL(spp); + + /* + * Notify Connectionless Service + */ + spanscls_detach(spp); + + /* + * Terminate all of our VCCs + */ + for (vcp = Q_HEAD(spp->sp_vccq, struct vccb); vcp; vcp = vnext) { + + vnext = Q_NEXT(vcp, struct vccb, vc_sigelem); + + /* + * Don't close the signalling VCC yet + */ + if (vcp->vc_connvc && vcp->vc_connvc->cvc_conn == + spp->sp_conn) + continue; + + /* + * Close VCC and notify owner + */ + err = spans_clear_vcc(spp, (struct spans_vccb *)vcp); + if (err) { + log(LOG_ERR, "spans: error %d clearing VCCB 0x%x\n", + err, vcp); + } + } + + /* + * Now close the SPANS signalling VCC + */ + if (cop = spp->sp_conn) { + err = atm_cm_release(cop, &spans_cause); + if (err) + ATM_DEBUG2( + "spans_detach: close failed for SPANS signalling channel; cop=0x%x, err=%d\n", + cop, err); + } + + + /* + * Get rid of protocol instance if there are no VCCs queued + */ + if (Q_HEAD(spp->sp_vccq, struct vccb) == NULL) { + struct sigmgr *smp = pip->pif_sigmgr; + + pip->pif_sigmgr = NULL; + pip->pif_siginst = NULL; + UNLINK((struct siginst *)spp, struct siginst, + smp->sm_prinst, si_next); + KM_FREE(spp, sizeof(struct spans), M_DEVBUF); + } else { + /* + * Otherwise, wait for protocol instance to be freed + * during spans_free processing for the last queued VCC. + */ + spp->sp_state = SPANS_DETACH; + } + + /* + * Log the fact that we've detached + */ + log(LOG_INFO, "spans: detached from interface %s%d\n", + pip->pif_name, pip->pif_unit); + + return (0); +} + + +/* + * Open a SPANS ATM Connection + * + * All service user requests to open a VC connection (via + * atm_open_connection) over an ATM interface attached to the SPANS + * signalling manager are handled here. + * + * Function will be called at splnet. + * + * Arguments: + * cvp pointer to user's requested connection parameters + * errp pointer to an int for extended error information + * + * Returns: + * CALL_PROCEEDING connection establishment is in progress + * CALL_FAILED connection establishment failed + * CALL_CONNECTED connection has been successfully established + * + */ +static int +spans_setup(cvp, errp) + Atm_connvc *cvp; + int *errp; +{ + struct atm_pif *pip = cvp->cvc_attr.nif->nif_pif; + struct spans *spp = (struct spans *)pip->pif_siginst; + int rc = 0; + + ATM_DEBUG1("spans_setup: cvp=0x%x\n", cvp); + + /* + * Intialize the returned error code + */ + *errp = 0; + + /* + * Open the connection + */ + switch (cvp->cvc_attr.called.addr.address_format) { + case T_ATM_PVC_ADDR: + /* + * Create a PVC + */ + *errp = spans_open_vcc(spp, cvp); + rc = (*errp ? CALL_FAILED : CALL_CONNECTED); + break; + + case T_ATM_SPANS_ADDR: + + /* + * Create an SVC + */ + *errp = spans_open_vcc(spp, cvp); + rc = (*errp ? CALL_FAILED : CALL_PROCEEDING); + break; + + default: + *errp = EPROTONOSUPPORT; + rc = CALL_FAILED; + } + + return (rc); +} + + +/* + * Close a SPANS ATM Connection + * + * All service user requests to terminate a previously open VC + * connection (via the atm_close_connection function), which is running + * over an interface attached to the SPANS signalling manager, are + * handled here. + * + * Function will be called at splnet. + * + * Arguments: + * vcp pointer to connection's VC control block + * errp pointer to an int for extended error information + * + * Returns: + * CALL_PROCEEDING connection termination is in progress + * CALL_FAILED connection termination failed + * CALL_CLEARED connection has been successfully terminated + * + */ +static int +spans_release(vcp, errp) + struct vccb *vcp; + int *errp; +{ + int rc = 0; + struct atm_pif *pip = vcp->vc_pif; + struct spans *spp = (struct spans *)pip->pif_siginst; + + ATM_DEBUG1("spans_release: vcp=0x%x\n", vcp); + + /* + * Initialize returned error code + */ + *errp = 0; + + /* + * Make sure VCC is open + */ + if ((vcp->vc_sstate == SPANS_VC_NULL) || + (vcp->vc_sstate == SPANS_VC_CLOSE) || + (vcp->vc_sstate == SPANS_VC_FREE) || + (vcp->vc_ustate == VCCU_NULL) || + (vcp->vc_ustate == VCCU_CLOSED)) { + *errp = EALREADY; + return(CALL_FAILED); + } + + /* + * Validate the connection type (PVC or SVC) + */ + if (!(vcp->vc_type & (VCC_PVC | VCC_SVC))) { + *errp = EPROTONOSUPPORT; + return(CALL_FAILED); + } + + /* + * Close the VCCB + */ + *errp = spans_close_vcc(spp, (struct spans_vccb *)vcp, FALSE); + + /* + * Set the return code + */ + if (vcp->vc_type & VCC_PVC) { + rc = (*errp ? CALL_FAILED : CALL_CLEARED); + } else { + rc = (*errp ? CALL_FAILED : CALL_PROCEEDING); + } + + return (rc); +} + + +/* + * Accept a SPANS Open from a remote host + * + * A user calls this routine (via the atm_accept_call function) + * after it is notified that an open request was received for it. + * + * Function will be called at splnet. + * + * Arguments: + * vcp pointer to user's VCCB + * errp pointer to an int for extended error information + * + * Returns: + * CALL_PROCEEDING connection establishment is in progress + * CALL_FAILED connection establishment failed + * CALL_CONNECTED connection has been successfully established + * + */ +static int +spans_accept(vcp, errp) + struct vccb *vcp; + int *errp; +{ + struct atm_pif *pip = vcp->vc_pif; + struct spans *spp = (struct spans *)pip->pif_siginst; + struct spans_vccb *svp = (struct spans_vccb *)vcp; + + ATM_DEBUG1("spans_accept: vcp=0x%x\n", vcp); + + /* + * Initialize the returned error code + */ + *errp = 0; + + /* + * Return an error if we're detaching + */ + if (spp->sp_state == SPANS_DETACH) { + *errp = ENETDOWN; + ATM_DEBUG0("spans_accept: detaching\n"); + return(CALL_FAILED); + } + + /* + * Respond to the open request + */ + *errp = spans_send_open_rsp(spp, svp, SPANS_OK); + if (*errp) { + ATM_DEBUG0("spans_accept: spans_send_open_rsp failed\n"); + goto failed; + } + + /* + * Update the VCC states + */ + svp->sv_sstate = SPANS_VC_OPEN; + svp->sv_ustate = VCCU_OPEN; + + return(CALL_CONNECTED); + +failed: + /* + * On error, free the VCCB and return CALL_FAILED + */ + svp->sv_sstate = SPANS_VC_FREE; + svp->sv_ustate = VCCU_CLOSED; + DEQUEUE(svp, struct spans_vccb, sv_sigelem, spp->sp_vccq); + spans_free((struct vccb *)svp); + + return(CALL_FAILED); +} + + +/* + * Reject a SPANS Open from a remote host + * + * A user calls this routine (via the atm_reject_call function) + * after it is notified that an open request was received for it. + * + * Function will be called at splnet. + * + * Arguments: + * vcp pointer to user's VCCB + * errp pointer to an int for extended error information + * + * Returns: + * CALL_CLEARED call request rejected + * CALL_FAILED call rejection failed + * + */ +static int +spans_reject(vcp, errp) + struct vccb *vcp; + int *errp; +{ + struct atm_pif *pip = vcp->vc_pif; + struct spans *spp = (struct spans *)pip->pif_siginst; + struct spans_vccb *svp = (struct spans_vccb *)vcp; + + ATM_DEBUG1("spans_reject: vcp=0x%x\n", vcp); + + /* + * Initialize the returned error code + */ + *errp = 0; + + /* + * Return an error if we're detaching + */ + if (spp->sp_state == SPANS_DETACH) { + *errp = ENETDOWN; + ATM_DEBUG0("spans_reject: detaching\n"); + return(CALL_FAILED); + } + + ATM_DEBUG1("spans_reject: cause code is %d\n", + vcp->vc_connvc->cvc_attr.cause.v.cause_value); + + /* + * Clean up the VCCB--the connection manager will free it + * spans_close_vcc will send a SPANS open response + */ + if (*errp = spans_close_vcc(spp, svp, TRUE)) { + ATM_DEBUG0("spans_reject: spans_close_vcc failed\n"); + return(CALL_FAILED); + } + + return(CALL_CLEARED); +} + + +/* + * Abort a SPANS ATM Connection + * + * All (non-user) requests to abort a previously open VC connection (via + * the atm_abort_connection function), which is running over an + * interface attached to the SPANS signalling manager, are handled here. + * The VCC owner will be notified of the request, in order to initiate + * termination of the connection. + * + * Function will be called at splnet. + * + * Arguments: + * vcp pointer to connection's VC control block + * + * Returns: + * 0 connection release was succesful + * errno connection release failed - reason indicated + * + */ +int +spans_abort(vcp) + struct vccb *vcp; +{ + + /* + * Make sure VCC is available + */ + if ((vcp->vc_sstate == SPANS_VC_NULL) || + (vcp->vc_sstate == SPANS_VC_CLOSE) || + (vcp->vc_sstate == SPANS_VC_FREE) || + (vcp->vc_ustate == VCCU_NULL) || + (vcp->vc_ustate == VCCU_CLOSED)) { + return(EALREADY); + } + + /* + * Only abort once + */ + if (vcp->vc_sstate == SPANS_VC_ABORT) { + return (EALREADY); + } + + /* + * Cancel any timer that might be running + */ + SPANS_VC_CANCEL(vcp); + + /* + * Set immediate timer to schedule connection termination + */ + vcp->vc_sstate = SPANS_VC_ABORT; + SPANS_VC_TIMER(vcp, 0); + + return (0); +} + + +/* + * Free SPANS ATM connection resources + * + * All service user requests to free the resources of a closed + * VCC connection (via the atm_free_connection function), which + * is running over an interface attached to the SigPVC signalling + * manager, are handled here. + * + * Function will be called at splnet. + * + * Arguments: + * vcp pointer to connection's VC control block + * + * Returns: + * 0 connection free was successful + * errno connection free failed - reason indicated + * + */ +int +spans_free(vcp) + struct vccb *vcp; +{ + struct atm_pif *pip = vcp->vc_pif; + struct spans *spp = (struct spans *)pip->pif_siginst; + + ATM_DEBUG1("spans_free: vcp = 0x%x\n", vcp); + + /* + * Make sure VCC has been closed + */ + if ((vcp->vc_ustate != VCCU_CLOSED) || + (vcp->vc_sstate != SPANS_VC_FREE)) { + ATM_DEBUG2("spans_free: bad state, sstate=%d, ustate=%d\n", + vcp->vc_sstate, vcp->vc_ustate); + return(EEXIST); + } + + /* + * Remove VCCB from protocol queue + */ + DEQUEUE(vcp, struct vccb, vc_sigelem, spp->sp_vccq); + + /* + * Free VCCB storage + */ + vcp->vc_ustate = VCCU_NULL; + vcp->vc_sstate = SPANS_VC_NULL; + atm_free((caddr_t)vcp); + + /* + * If we're detaching and this was the last VCC queued, + * get rid of the protocol instance + */ + if ((spp->sp_state == SPANS_DETACH) && + (Q_HEAD(spp->sp_vccq, struct vccb) == NULL)) { + struct sigmgr *smp = pip->pif_sigmgr; + + pip->pif_sigmgr = NULL; + pip->pif_siginst = NULL; + UNLINK((struct siginst *)spp, struct siginst, smp->sm_prinst, + si_next); + KM_FREE(spp, sizeof(struct spans), M_DEVBUF); + } + + return (0); +} + + +/* + * SPANS IOCTL support + * + * Function will be called at splnet. + * + * Arguments: + * code PF_ATM sub-operation code + * data pointer to code specific parameter data area + * arg1 pointer to code specific argument + * + * Returns: + * 0 request procesed + * errno error processing request - reason indicated + * + */ +static int +spans_ioctl(code, data, arg1) + int code; + caddr_t data; + caddr_t arg1; +{ + struct atmdelreq *adp; + struct atminfreq *aip; + struct spans *spp; + struct spans_vccb *svp; + struct air_vcc_rsp rsp; + Atm_connection *cop; + int buf_len, err = 0, i, vpi, vci; + caddr_t buf_addr; + + + switch (code) { + + case AIOCS_DEL_PVC: + case AIOCS_DEL_SVC: + /* + * Delete a VCC + */ + adp = (struct atmdelreq *)data; + spp = (struct spans *)arg1; + + /* + * Don't let a user close the SPANS signalling VC or + * the SPANS CLS VC + */ + vpi = adp->adr_pvc_vpi; + vci = adp->adr_pvc_vci; + if ((vpi == SPANS_SIG_VPI && vci == SPANS_SIG_VCI) || + (vpi == SPANS_CLS_VPI && + vci == SPANS_CLS_VCI)) + return(EINVAL); + + /* + * Find requested VCC + */ + for (svp = Q_HEAD(spp->sp_vccq, struct spans_vccb); svp; + svp = Q_NEXT(svp, struct spans_vccb, sv_sigelem)) { + if ((svp->sv_vpi == vpi) && (svp->sv_vci == vci)) + break; + } + if (svp == NULL) + return (ENOENT); + + /* + * Check VCC type + */ + switch (code) { + case AIOCS_DEL_PVC: + if (!(svp->sv_type & VCC_PVC)) { + return(EINVAL); + } + break; + case AIOCS_DEL_SVC: + if (!(svp->sv_type & VCC_SVC)) { + return(EINVAL); + } + break; + } + + /* + * Schedule VCC termination + */ + err = spans_abort((struct vccb *)svp); + break; + + case AIOCS_INF_VCC: + /* + * Return VCC information + */ + aip = (struct atminfreq *)data; + spp = (struct spans *)arg1; + + buf_addr = aip->air_buf_addr; + buf_len = aip->air_buf_len; + + /* + * Loop through the VCC queue + */ + for (svp = Q_HEAD(spp->sp_vccq, struct spans_vccb); svp; + svp = Q_NEXT(svp, struct spans_vccb, sv_sigelem)) { + /* + * Make sure there's room in the user's buffer + */ + if (buf_len < sizeof(rsp)) { + err = ENOSPC; + break; + } + + /* + * Fill out the response struct for the VCC + */ + (void) sprintf(rsp.avp_intf, "%s%d", + spp->sp_pif->pif_name, + spp->sp_pif->pif_unit); + rsp.avp_vpi = svp->sv_vpi; + rsp.avp_vci = svp->sv_vci; + rsp.avp_type = svp->sv_type; + rsp.avp_aal = svp->sv_connvc->cvc_attr.aal.type; + rsp.avp_sig_proto = svp->sv_proto; + cop = svp->sv_connvc->cvc_conn; + if (cop) + rsp.avp_encaps = cop->co_mpx; + else + rsp.avp_encaps = 0; + rsp.avp_state = svp->sv_sstate; + KM_ZERO(rsp.avp_owners, sizeof(rsp.avp_owners)); + for (i = 0; cop && i < sizeof(rsp.avp_owners); + cop = cop->co_next, + i += T_ATM_APP_NAME_LEN+1) { + strncpy(&rsp.avp_owners[i], + cop->co_endpt->ep_getname(cop->co_toku), + T_ATM_APP_NAME_LEN); + } + rsp.avp_daddr.address_format = T_ATM_SPANS_ADDR; + rsp.avp_daddr.address_length = + sizeof(Atm_addr_spans); + if (svp->sv_type & VCC_OUT) { + spans_addr_copy(&svp->sv_conn.con_dst, + rsp.avp_daddr.address); + } else { + spans_addr_copy(&svp->sv_conn.con_src, + rsp.avp_daddr.address); + } + rsp.avp_dsubaddr.address_format = T_ATM_ABSENT; + rsp.avp_dsubaddr.address_length = 0; + rsp.avp_ipdus = svp->sv_ipdus; + rsp.avp_opdus = svp->sv_opdus; + rsp.avp_ibytes = svp->sv_ibytes; + rsp.avp_obytes = svp->sv_obytes; + rsp.avp_ierrors = svp->sv_ierrors; + rsp.avp_oerrors = svp->sv_oerrors; + rsp.avp_tstamp = svp->sv_tstamp; + + /* + * Copy the response into the user's buffer + */ + if (err = copyout((caddr_t)&rsp, buf_addr, + sizeof(rsp))) + break; + buf_addr += sizeof(rsp); + buf_len -= sizeof(rsp); + } + + /* + * Update the buffer pointer and length + */ + aip->air_buf_addr = buf_addr; + aip->air_buf_len = buf_len; + break; + + case AIOCS_ADD_ARP: + case AIOCS_DEL_ARP: + case AIOCS_INF_ARP: + case AIOCS_INF_ASV: + /* + * ARP specific ioctl's + */ + err = spansarp_ioctl(code, data, arg1); + break; + + default: + err = EOPNOTSUPP; + } + + return (err); +} + + +#ifdef ATM_SPANS_MODULE +/* + ******************************************************************* + * + * Loadable Module Support + * + ******************************************************************* + */ +static int spans_doload __P((void)); +static int spans_dounload __P((void)); + +/* + * Generic module load processing + * + * This function is called by an OS-specific function when this + * module is being loaded. + * + * Arguments: + * none + * + * Returns: + * 0 load was successful + * errno load failed - reason indicated + * + */ +static int +spans_doload() +{ + int err = 0; + + /* + * Start us up + */ + err = spans_start(); + if (err) + /* Problems, clean up */ + (void)spans_stop(); + + return (err); +} + + +/* + * Generic module unload processing + * + * This function is called by an OS-specific function when this + * module is being unloaded. + * + * Arguments: + * none + * + * Returns: + * 0 unload was successful + * errno unload failed - reason indicated + * + */ +static int +spans_dounload() +{ + int err = 0; + + /* + * OK, try to clean up our mess + */ + err = spans_stop(); + + return (err); +} + + +#ifdef sun +/* + * Loadable driver description + */ +struct vdldrv spans_drv = { + VDMAGIC_PSEUDO, /* Pseudo Driver */ + "spans_mod", /* name */ + NULL, /* dev_ops */ + NULL, /* bdevsw */ + NULL, /* cdevsw */ + 0, /* blockmajor */ + 0 /* charmajor */ +}; + + +/* + * Loadable module support entry point + * + * This is the routine called by the vd driver for all loadable module + * functions for this pseudo driver. This routine name must be specified + * on the modload(1) command. This routine will be called whenever the + * modload(1), modunload(1) or modstat(1) commands are issued for this + * module. + * + * Arguments: + * cmd vd command code + * vdp pointer to vd driver's structure + * vdi pointer to command-specific vdioctl_* structure + * vds pointer to status structure (VDSTAT only) + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +int +spans_mod(cmd, vdp, vdi, vds) + int cmd; + struct vddrv *vdp; + caddr_t vdi; + struct vdstat *vds; +{ + int err = 0; + + switch (cmd) { + + case VDLOAD: + /* + * Module Load + * + * We dont support any user configuration + */ + err = spans_doload(); + if (err == 0) + /* Let vd driver know about us */ + vdp->vdd_vdtab = (struct vdlinkage *)&spans_drv; + break; + + case VDUNLOAD: + /* + * Module Unload + */ + err = spans_dounload(); + break; + + case VDSTAT: + /* + * Module Status + */ + + /* Not much to say at the moment */ + + break; + + default: + log(LOG_ERR, "spans_mod: Unknown vd command 0x%x\n", cmd); + err = EINVAL; + } + + return (err); +} +#endif /* sun */ + +#ifdef __FreeBSD__ + +#include <sys/exec.h> +#include <sys/sysent.h> +#include <sys/lkm.h> + +/* + * Loadable miscellaneous module description + */ +MOD_MISC(spans); + + +/* + * Loadable module support "load" entry point + * + * This is the routine called by the lkm driver whenever the + * modload(1) command is issued for this module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +static int +spans_load(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + return(spans_doload()); +} + + +/* + * Loadable module support "unload" entry point + * + * This is the routine called by the lkm driver whenever the + * modunload(1) command is issued for this module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +static int +spans_unload(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + return(spans_dounload()); +} + + +/* + * Loadable module support entry point + * + * This is the routine called by the lkm driver for all loadable module + * functions for this driver. This routine name must be specified + * on the modload(1) command. This routine will be called whenever the + * modload(1), modunload(1) or modstat(1) commands are issued for this + * module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * ver lkm version + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +int +spans_mod(lkmtp, cmd, ver) + struct lkm_table *lkmtp; + int cmd; + int ver; +{ + MOD_DISPATCH(spans, lkmtp, cmd, ver, + spans_load, spans_unload, lkm_nullcmd); +} +#endif /* __FreeBSD__ */ + +#else /* !ATM_SPANS_MODULE */ + +/* + ******************************************************************* + * + * Kernel Compiled Module Support + * + ******************************************************************* + */ +static void spans_doload __P((void *)); + +SYSINIT(atmspans, SI_SUB_PROTO_END, SI_ORDER_ANY, spans_doload, NULL) + +/* + * Kernel initialization + * + * Arguments: + * arg Not used + * + * Returns: + * none + * + */ +static void +spans_doload(void *arg) +{ + int err = 0; + + /* + * Start us up + */ + err = spans_start(); + if (err) { + /* Problems, clean up */ + (void)spans_stop(); + + log(LOG_ERR, "ATM SPANS unable to initialize (%d)!!\n", err); + } + return; +} +#endif /* ATM_SPANS_MODULE */ + diff --git a/sys/netatm/spans/spans_kxdr.c b/sys/netatm/spans/spans_kxdr.c new file mode 100644 index 0000000..b6534de --- /dev/null +++ b/sys/netatm/spans/spans_kxdr.c @@ -0,0 +1,684 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: spans_kxdr.c,v 1.2 1997/05/06 22:17:00 mks Exp $ + * + */ + +/* + * SPANS Signalling Manager + * --------------------------- + * + * Kernel XDR (External Data Representation) routines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: spans_kxdr.c,v 1.2 1997/05/06 22:17:00 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +/* + * This file contains code that has been copied and/or modified from + * the following FreeBSD files: + * + * /usr/src/lib/libc/xdr/xdr.c + * /usr/src/lib/libc/xdr/xdr_mem.c + * + * which are covered by the copyright notice below. + */ + +/* + * Sun RPC is a product of Sun Microsystems, Inc. and is provided for + * unrestricted use provided that this legend is included on all tape + * media and as a part of the software program in whole or part. Users + * may copy or modify Sun RPC without charge, but are not authorized + * to license or distribute it to anyone else except as part of a product or + * program developed by the user. + * + * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE + * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR + * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE. + * + * Sun RPC is provided with no support and without any obligation on the + * part of Sun Microsystems, Inc. to assist in its use, correction, + * modification or enhancement. + * + * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE + * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC + * OR ANY PART THEREOF. + * + * In no event will Sun Microsystems, Inc. be liable for any lost revenue + * or profits or other special, indirect and consequential damages, even if + * Sun has been advised of the possibility of such damages. + * + * Sun Microsystems, Inc. + * 2550 Garcia Avenue + * Mountain View, California 94043 + */ + +#if !defined(sun) + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)xdr.c 1.35 87/08/12";*/ +/*static char *sccsid = "from: @(#)xdr.c 2.1 88/07/29 4.0 RPCSRC";*/ +/*static char *rcsid = "Id: xdr.c,v 1.2.4.2 1996/06/05 02:52:02 jkh Exp";*/ +#endif + +/* + * xdr.c, Generic XDR routines implementation. + * + * Copyright (C) 1986, Sun Microsystems, Inc. + * + * These are the "generic" xdr routines used to serialize and de-serialize + * most common data items. See xdr.h for more info on the interface to + * xdr. + */ + +#include <rpc/types.h> +#include <rpc/xdr.h> + +/* + * constants specific to the xdr "protocol" + */ +#define XDR_FALSE ((long) 0) +#define XDR_TRUE ((long) 1) +#define LASTUNSIGNED ((u_int) 0-1) + +/* + * for unit alignment + */ +static char xdr_zero[BYTES_PER_XDR_UNIT] = { 0, 0, 0, 0 }; + +/* + * XDR integers + */ +bool_t +xdr_int(xdrs, ip) + XDR *xdrs; + int *ip; +{ + +#ifdef lint + (void) (xdr_short(xdrs, (short *)ip)); + return (xdr_long(xdrs, (long *)ip)); +#else + if (sizeof (int) == sizeof (long)) { + return (xdr_long(xdrs, (long *)ip)); + } else { + return (xdr_short(xdrs, (short *)ip)); + } +#endif +} + +/* + * XDR unsigned integers + */ +bool_t +xdr_u_int(xdrs, up) + XDR *xdrs; + u_int *up; +{ + +#ifdef lint + (void) (xdr_short(xdrs, (short *)up)); + return (xdr_u_long(xdrs, (u_long *)up)); +#else + if (sizeof (u_int) == sizeof (u_long)) { + return (xdr_u_long(xdrs, (u_long *)up)); + } else { + return (xdr_short(xdrs, (short *)up)); + } +#endif +} + +/* + * XDR long integers + * same as xdr_u_long - open coded to save a proc call! + */ +bool_t +xdr_long(xdrs, lp) + register XDR *xdrs; + long *lp; +{ + + if (xdrs->x_op == XDR_ENCODE) + return (XDR_PUTLONG(xdrs, lp)); + + if (xdrs->x_op == XDR_DECODE) + return (XDR_GETLONG(xdrs, lp)); + + if (xdrs->x_op == XDR_FREE) + return (TRUE); + + return (FALSE); +} + +/* + * XDR unsigned long integers + * same as xdr_long - open coded to save a proc call! + */ +bool_t +xdr_u_long(xdrs, ulp) + register XDR *xdrs; + u_long *ulp; +{ + + if (xdrs->x_op == XDR_DECODE) + return (XDR_GETLONG(xdrs, (long *)ulp)); + if (xdrs->x_op == XDR_ENCODE) + return (XDR_PUTLONG(xdrs, (long *)ulp)); + if (xdrs->x_op == XDR_FREE) + return (TRUE); + return (FALSE); +} + +/* + * XDR short integers + */ +bool_t +xdr_short(xdrs, sp) + register XDR *xdrs; + short *sp; +{ + long l; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + l = (long) *sp; + return (XDR_PUTLONG(xdrs, &l)); + + case XDR_DECODE: + if (!XDR_GETLONG(xdrs, &l)) { + return (FALSE); + } + *sp = (short) l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + return (FALSE); +} + +/* + * XDR unsigned short integers + */ +bool_t +xdr_u_short(xdrs, usp) + register XDR *xdrs; + u_short *usp; +{ + u_long l; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + l = (u_long) *usp; + return (XDR_PUTLONG(xdrs, &l)); + + case XDR_DECODE: + if (!XDR_GETLONG(xdrs, &l)) { + return (FALSE); + } + *usp = (u_short) l; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + return (FALSE); +} + + +/* + * XDR a char + */ +bool_t +xdr_char(xdrs, cp) + XDR *xdrs; + char *cp; +{ + int i; + + i = (*cp); + if (!xdr_int(xdrs, &i)) { + return (FALSE); + } + *cp = i; + return (TRUE); +} + +/* + * XDR an unsigned char + */ +bool_t +xdr_u_char(xdrs, cp) + XDR *xdrs; + u_char *cp; +{ + u_int u; + + u = (*cp); + if (!xdr_u_int(xdrs, &u)) { + return (FALSE); + } + *cp = u; + return (TRUE); +} + +/* + * XDR booleans + */ +bool_t +xdr_bool(xdrs, bp) + register XDR *xdrs; + bool_t *bp; +{ + long lb; + + switch (xdrs->x_op) { + + case XDR_ENCODE: + lb = *bp ? XDR_TRUE : XDR_FALSE; + return (XDR_PUTLONG(xdrs, &lb)); + + case XDR_DECODE: + if (!XDR_GETLONG(xdrs, &lb)) { + return (FALSE); + } + *bp = (lb == XDR_FALSE) ? FALSE : TRUE; + return (TRUE); + + case XDR_FREE: + return (TRUE); + } + return (FALSE); +} + +/* + * XDR enumerations + */ +bool_t +xdr_enum(xdrs, ep) + XDR *xdrs; + enum_t *ep; +{ +#ifndef lint + enum sizecheck { SIZEVAL }; /* used to find the size of an enum */ + + /* + * enums are treated as ints + */ + if (sizeof (enum sizecheck) == sizeof (long)) { + return (xdr_long(xdrs, (long *)ep)); + } else if (sizeof (enum sizecheck) == sizeof (short)) { + return (xdr_short(xdrs, (short *)ep)); + } else { + return (FALSE); + } +#else + (void) (xdr_short(xdrs, (short *)ep)); + return (xdr_long(xdrs, (long *)ep)); +#endif +} + +/* + * XDR opaque data + * Allows the specification of a fixed size sequence of opaque bytes. + * cp points to the opaque object and cnt gives the byte length. + */ +bool_t +xdr_opaque(xdrs, cp, cnt) + register XDR *xdrs; + caddr_t cp; + register u_int cnt; +{ + register u_int rndup; + static char crud[BYTES_PER_XDR_UNIT]; + + /* + * if no data we are done + */ + if (cnt == 0) + return (TRUE); + + /* + * round byte count to full xdr units + */ + rndup = cnt % BYTES_PER_XDR_UNIT; + if (rndup > 0) + rndup = BYTES_PER_XDR_UNIT - rndup; + + if (xdrs->x_op == XDR_DECODE) { + if (!XDR_GETBYTES(xdrs, cp, cnt)) { + return (FALSE); + } + if (rndup == 0) + return (TRUE); + return (XDR_GETBYTES(xdrs, crud, rndup)); + } + + if (xdrs->x_op == XDR_ENCODE) { + if (!XDR_PUTBYTES(xdrs, cp, cnt)) { + return (FALSE); + } + if (rndup == 0) + return (TRUE); + return (XDR_PUTBYTES(xdrs, xdr_zero, rndup)); + } + + if (xdrs->x_op == XDR_FREE) { + return (TRUE); + } + + return (FALSE); +} + + +/* + * XDR implementation using kernel buffers + */ + +#if defined(LIBC_SCCS) && !defined(lint) +/*static char *sccsid = "from: @(#)xdr_mem.c 1.19 87/08/11 Copyr 1984 Sun Micro";*/ +/*static char *sccsid = "from: @(#)xdr_mem.c 2.1 88/07/29 4.0 RPCSRC";*/ +/*static char *rcsid = "Id: xdr_mem.c,v 1.2.4.2 1996/06/05 02:52:04 jkh Exp";*/ +#endif + +/* + * xdr_mem.h, XDR implementation using memory buffers. + * + * Copyright (C) 1984, Sun Microsystems, Inc. + * + * If you have some data to be interpreted as external data representation + * or to be converted to external data representation in a memory buffer, + * then this is the package for you. + * + */ + + +void xdrmbuf_init __P((XDR *, KBuffer *, enum xdr_op)); +static bool_t xdrmbuf_getlong __P((XDR *, long *)); +static bool_t xdrmbuf_putlong __P((XDR *, long *)); +static bool_t xdrmbuf_getbytes __P((XDR *, caddr_t, u_int)); +static bool_t xdrmbuf_putbytes __P((XDR *, caddr_t, u_int)); +static u_int xdrmbuf_getpos __P((XDR *)); + +static struct xdr_ops xdrmbuf_ops = { + xdrmbuf_getlong, + xdrmbuf_putlong, + xdrmbuf_getbytes, + xdrmbuf_putbytes, + xdrmbuf_getpos, + NULL, + NULL, + NULL +}; + +/* + * The procedure xdrmbuf_init initializes a stream descriptor for a + * kernel buffer. + */ +void +xdrmbuf_init(xdrs, m, op) + register XDR *xdrs; + KBuffer *m; + enum xdr_op op; +{ + + xdrs->x_op = op; + xdrs->x_ops = &xdrmbuf_ops; + xdrs->x_base = (caddr_t)m; + KB_DATASTART(m, xdrs->x_private, caddr_t); + xdrs->x_handy = KB_LEN(m); +} + +static bool_t +xdrmbuf_getlong(xdrs, lp) + register XDR *xdrs; + long *lp; +{ + + /* + * See if long is contained in this buffer + */ + if ((xdrs->x_handy -= sizeof(long)) < 0) { + register KBuffer *m; + + /* + * We (currently) don't allow a long to span a buffer + */ + if (xdrs->x_handy != -sizeof(long)) { + printf("xdrmbuf_getlong: data spans buffers\n"); + return (FALSE); + } + + /* + * Try to move to a chained buffer + */ + if ((m = (KBuffer *)(xdrs->x_base)) != NULL) { + m = KB_NEXT(m); + xdrs->x_base = (caddr_t)m; + } + if (m) { + /* + * Setup new buffer's info + */ + KB_DATASTART(m, xdrs->x_private, caddr_t); + if ((xdrs->x_handy = KB_LEN(m) - sizeof(long)) < 0) { + printf("xdrmbuf_getlong: short buffer\n"); + return (FALSE); + } + } else { + /* + * No more buffers + */ + return (FALSE); + } + } + + /* + * Return the long value + */ + *lp = (long)ntohl((u_long)(*((long *)(xdrs->x_private)))); + + /* + * Advance the data stream + */ + xdrs->x_private += sizeof(long); + return (TRUE); +} + +static bool_t +xdrmbuf_putlong(xdrs, lp) + register XDR *xdrs; + long *lp; +{ + + /* + * See if long will fit in this buffer + */ + if ((xdrs->x_handy -= sizeof(long)) < 0) { + register KBuffer *m; + + /* + * We (currently) don't allow a long to span a buffer + */ + if (xdrs->x_handy != -sizeof(long)) { + printf("xdrmbuf_putlong: data spans buffers\n"); + return (FALSE); + } + + /* + * Try to move to a chained buffer + */ + if ((m = (KBuffer *)(xdrs->x_base)) != NULL) { + m = KB_NEXT(m); + xdrs->x_base = (caddr_t)m; + } + if (m) { + /* + * Setup new buffer's info + */ + KB_DATASTART(m, xdrs->x_private, caddr_t); + if ((xdrs->x_handy = KB_LEN(m) - sizeof(long)) < 0) { + printf("xdrmbuf_putlong: short buffer\n"); + return (FALSE); + } + } else { + /* + * No more buffers + */ + return (FALSE); + } + } + + /* + * Store the long value into our buffer + */ + *(long *)xdrs->x_private = (long)htonl((u_long)(*lp)); + + /* + * Advance the data stream + */ + xdrs->x_private += sizeof(long); + return (TRUE); +} + +static bool_t +xdrmbuf_getbytes(xdrs, addr, len) + register XDR *xdrs; + caddr_t addr; + register u_int len; +{ + + while (len > 0) { + u_int copy; + + if (xdrs->x_handy <= 0) { + register KBuffer *m; + + /* + * No data in current buffer, move to a chained buffer + */ + if ((m = (KBuffer *)(xdrs->x_base)) != NULL) { + m = KB_NEXT(m); + xdrs->x_base = (caddr_t)m; + } + if (m) { + /* + * Setup new buffer's info + */ + KB_DATASTART(m, xdrs->x_private, caddr_t); + xdrs->x_handy = KB_LEN(m); + } else { + /* + * No more buffers + */ + return (FALSE); + } + } + + /* + * Copy from buffer to user's space + */ + copy = MIN(len, xdrs->x_handy); + KM_COPY(xdrs->x_private, addr, copy); + + /* + * Update data stream controls + */ + xdrs->x_private += copy; + xdrs->x_handy -= copy; + addr += copy; + len -= copy; + } + return (TRUE); +} + +static bool_t +xdrmbuf_putbytes(xdrs, addr, len) + register XDR *xdrs; + caddr_t addr; + register u_int len; +{ + + while (len > 0) { + u_int copy; + + if (xdrs->x_handy <= 0) { + register KBuffer *m; + + /* + * No data in current buffer, move to a chained buffer + */ + if ((m = (KBuffer *)(xdrs->x_base)) != NULL) { + m = KB_NEXT(m); + xdrs->x_base = (caddr_t)m; + } + if (m) { + /* + * Setup new buffer's info + */ + KB_DATASTART(m, xdrs->x_private, caddr_t); + xdrs->x_handy = KB_LEN(m); + } else { + /* + * No more buffers + */ + return (FALSE); + } + } + + /* + * Copy from user's space into buffer + */ + copy = MIN(len, xdrs->x_handy); + KM_COPY(addr, xdrs->x_private, copy); + + /* + * Update data stream controls + */ + xdrs->x_private += copy; + xdrs->x_handy -= copy; + addr += copy; + len -= copy; + } + return (TRUE); +} + +static u_int +xdrmbuf_getpos(xdrs) + register XDR *xdrs; +{ + + return ((u_int)xdrs->x_private - (u_int)xdrs->x_base); +} + +#endif /* !defined(sun) */ + diff --git a/sys/netatm/spans/spans_msg.c b/sys/netatm/spans/spans_msg.c new file mode 100644 index 0000000..0dc5df9 --- /dev/null +++ b/sys/netatm/spans/spans_msg.c @@ -0,0 +1,1633 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: spans_msg.c,v 1.8 1998/08/26 23:29:09 mks Exp $ + * + */ + +/* + * SPANS Signalling Manager + * --------------------------- + * + * SPANS signalling message processing. + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: spans_msg.c,v 1.8 1998/08/26 23:29:09 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <rpc/rpc.h> +#include "spans_xdr.h" +#include <netatm/spans/spans_var.h> + +/* + * External functions + */ +void xdrmbuf_init __P((XDR *, KBuffer *, enum xdr_op)); + +/* + * Local functions + */ +static void spans_host_link __P((struct spans *, long)); +static void spans_status_ind __P((struct spans *, spans_msg *)); +static void spans_status_rsp __P((struct spans *, spans_msg *)); +static void spans_open_req __P((struct spans *, spans_msg *)); +static void spans_open_rsp __P((struct spans *, spans_msg *)); +static void spans_close_req __P((struct spans *, spans_msg *)); +static void spans_close_rsp __P((struct spans *, spans_msg *)); +static void spans_multi_req __P((struct spans *, spans_msg *)); +static void spans_add_req __P((struct spans *, spans_msg *)); +static void spans_join_req __P((struct spans *, spans_msg *)); +static void spans_leave_req __P((struct spans *, spans_msg *)); +static void spans_vcir_ind __P((struct spans *, spans_msg *)); +static void spans_query_req __P((struct spans *, spans_msg *)); + + +/* + * Called to set status when a status message comes in from a host + * connected back-to-back with us. Check the epoch and, if it has + * changed, set the appropriate state and save updated state + * information. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * host_epoch epoch of host at far end of link + * + * Returns: + * 0 message sent OK + * errno error encountered + * + */ +static void +spans_host_link(spp, host_epoch) + struct spans *spp; + long host_epoch; +{ + struct atm_pif *pip = spp->sp_pif; + + /* + * There's a host at the other end of the link. If its + * epoch has changed, clean up our state and save the + * new information. + */ + if (spp->sp_s_epoch != host_epoch) { + spp->sp_s_epoch = host_epoch; + spans_switch_reset(spp, SPANS_UNI_UP); + spp->sp_addr.address_format = T_ATM_SPANS_ADDR; + spp->sp_addr.address_length = sizeof(spans_addr); + KM_COPY(&pip->pif_macaddr.ma_data[2], + &spp->sp_addr.address[4], + 4); + log(LOG_INFO, + "spans: using SPANS address of %s on interface %s%d\n", + spans_addr_print((spans_addr *)spp->sp_addr.address), + pip->pif_name, + pip->pif_unit); + } +} + +/* + * Send a SPANS signalling message + * + * Called to send a SPANS message. This routine gets a buffer, performs + * XDR processing, and hands the message to the AAL for transmission. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to status message + * + * Returns: + * 0 message sent OK + * errno error encountered + * + */ +int +spans_send_msg(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + int err = 0; + KBuffer *m; + XDR xdrs; + +#ifdef NOTDEF + ATM_DEBUG2("spans_send_msg: msg=0x%x, type=%d\n", msg, + msg->sm_type); + if (msg->sm_type != SPANS_STAT_REQ && + msg->sm_type != SPANS_STAT_IND && + msg->sm_type != SPANS_STAT_RSP) { + printf("spans_send_msg: sending "); + spans_print_msg(msg); + } +#endif + + /* + * If the signalling channel has been closed, don't do anything + */ + if (!spp->sp_conn) + return(ECONNABORTED); + + /* + * Get a buffer + */ + KB_ALLOCPKT(m, sizeof(spans_msg), KB_F_NOWAIT, KB_T_DATA); + if (m == NULL) { + /* No buffer available */ + return(ENOBUFS); + } + + /* + * Convert message to network order + */ + KB_LEN(m) = KB_BFRLEN(m); + xdrmbuf_init(&xdrs, m, XDR_ENCODE); + if (!xdr_spans_msg(&xdrs, msg)) { + log(LOG_ERR, "spans_send_msg: XDR encode failed\n"); + KB_LEN(m) = XDR_GETPOS(&xdrs); + spans_dump_buffer(m); + KB_FREEALL(m); + return(EIO); + } + KB_LEN(m) = XDR_GETPOS(&xdrs); + + /* + * Send the message + */ + err = atm_cm_cpcs_data(spp->sp_conn, m); + if (err) + KB_FREEALL(m); + + return(err); +} + + +/* + * Send an open request + * + * Build and send an open request. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * svp pointer to VCCB for which the request is being sent + * + * Returns: + * none + * + */ +int +spans_send_open_req(spp, svp) + struct spans *spp; + struct spans_vccb *svp; +{ + spans_msg *req; + int err = 0; + + ATM_DEBUG1("spans_send_open_req: svp=0x%x\n", svp); + + /* + * Get memory for a request message + */ + req = (spans_msg *)atm_allocate(&spans_msgpool); + if (req == NULL) { + err = ENOBUFS; + goto done; + } + + /* + * Fill in the request + */ + req->sm_vers = SPANS_VERS_1_0; + req->sm_type = SPANS_OPEN_REQ; + req->sm_open_req.opreq_conn = svp->sv_conn; + req->sm_open_req.opreq_aal = svp->sv_spans_aal; + req->sm_open_req.opreq_desrsrc = svp->sv_spans_qos; + req->sm_open_req.opreq_minrsrc.rsc_peak = 0; + req->sm_open_req.opreq_minrsrc.rsc_mean = 0; + req->sm_open_req.opreq_minrsrc.rsc_burst = 0; + req->sm_open_req.opreq_vpvc.vpf_valid = FALSE; + + /* + * Send the request + */ + err = spans_send_msg(spp, req); + atm_free(req); + +done: + return(err); +} + + +/* + * Send an open response + * + * Build and send a response to an open request or open indication. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * svp pointer to VCCB for which the response is being sent + * result result code to include in the response + * + * Returns: + * none + * + */ +int +spans_send_open_rsp(spp, svp, result) + struct spans *spp; + struct spans_vccb *svp; + spans_result result; +{ + spans_msg *rsp; + int rc; + + ATM_DEBUG2("spans_send_open_rsp: svp=0x%x, result=%d\n", svp, + result); + + /* + * Get memory for a response message + */ + rsp = (spans_msg *)atm_allocate(&spans_msgpool); + if (rsp == NULL) + return(ENOBUFS); + + /* + * Fill in the response + */ + rsp->sm_vers = SPANS_VERS_1_0; + rsp->sm_type = SPANS_OPEN_RSP; + rsp->sm_open_rsp.oprsp_conn = svp->sv_conn; + rsp->sm_open_rsp.oprsp_result = result; + rsp->sm_open_rsp.oprsp_rsrc = svp->sv_spans_qos; + rsp->sm_open_rsp.oprsp_vpvc = + SPANS_PACK_VPIVCI(svp->sv_vpi, svp->sv_vci); + + /* + * Send the response + */ + rc = spans_send_msg(spp, rsp); + atm_free(rsp); + + return(rc); +} + + +/* + * Send a close request + * + * Called to send a close request. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * svp pointer to VCCB for which the close is being sent + * + * Returns: + * none + * + */ +int +spans_send_close_req(spp, svp) + struct spans *spp; + struct spans_vccb *svp; +{ + spans_msg *req; + int err = 0; + + ATM_DEBUG1("spans_send_close_req: svp=0x%x\n", svp); + + /* + * Get memory for a close request + */ + req = (spans_msg *)atm_allocate(&spans_msgpool); + if (req == NULL) { + err = ENOBUFS; + goto done; + } + + /* + * Fill in the request + */ + req->sm_vers = SPANS_VERS_1_0; + if (svp->sv_type & VCC_OUT) { + req->sm_type = SPANS_CLOSE_REQ; + } else if (svp->sv_type & VCC_IN) { + req->sm_type = SPANS_RCLOSE_REQ; + } else { + err = EINVAL; + ATM_DEBUG1( + "spans_send_close_req: invalid VCCB type 0x%x\n", + svp->sv_type); + goto done; + } + req->sm_close_req.clreq_conn = svp->sv_conn; + + /* + * Send the close request + */ + err = spans_send_msg(spp, req); + +done: + if (req) + atm_free(req); + + return(err); +} + + + +/* + * Process a status indication or status request + * + * Called when a status indication or status request is received. + * Processing will be based on the current SPANS state. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the status message + * + * Returns: + * none + * + */ +static void +spans_status_ind(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + spans_msg *rsp_msg; + struct atm_pif *pip = spp->sp_pif; + + /* + * Reset the probe count. + */ + spp->sp_probe_ct = 0; + + switch (spp->sp_state) { + case SPANS_PROBE: + /* + * Interface just came up, update signalling state + */ + spp->sp_state = SPANS_ACTIVE; + break; + + case SPANS_ACTIVE: + break; + + default: + log(LOG_ERR, "spans: received status msg in state %d\n", + spp->sp_state); + } + + /* + * Process the message + */ + switch (msg->sm_type) { + + case SPANS_STAT_REQ: + /* + * Handle a request from a host at the other end of + * the link. + */ + spans_host_link(spp, msg->sm_stat_req.streq_es_epoch); + break; + + case SPANS_STAT_IND: + + /* + * There's a switch at the other end of the link. If + * its epoch has changed, reset the SPANS state and save + * the new information. + */ + if (spp->sp_s_epoch != + msg->sm_stat_ind.stind_sw_epoch) { + spans_switch_reset(spp, SPANS_UNI_UP); + spp->sp_s_epoch = + msg->sm_stat_ind.stind_sw_epoch; + spp->sp_addr.address_format = T_ATM_SPANS_ADDR; + spp->sp_addr.address_length = + sizeof(spans_addr); + spans_addr_copy(&msg->sm_stat_ind.stind_es_addr, + spp->sp_addr.address); + log(LOG_INFO, + "spans: received SPANS address %s from switch for interface %s%d\n", + spans_addr_print((spans_addr *)spp->sp_addr.address), + pip->pif_name, + pip->pif_unit); + } + break; + + default: + ATM_DEBUG1("spans_status_ind: Invalid message type %d\n", + msg->sm_type); + return; + } + + /* + * Respond to the status request or indication with a + * status response + */ + rsp_msg = (spans_msg *)atm_allocate(&spans_msgpool); + if (rsp_msg == NULL) + return; + rsp_msg->sm_vers = SPANS_VERS_1_0; + rsp_msg->sm_type = SPANS_STAT_RSP; + rsp_msg->sm_stat_rsp.strsp_es_epoch = spp->sp_h_epoch; + spans_addr_copy(spp->sp_addr.address, + &rsp_msg->sm_stat_rsp.strsp_es_addr); + spans_send_msg(spp, rsp_msg); + atm_free(rsp_msg); +} + + + +/* + * Process a status response + * + * Called when a status response is received. + * Processing will be based on the current SPANS state. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the status response message + * + * Returns: + * none + * + */ +static void +spans_status_rsp(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + + /* + * Reset the probe count. + */ + spp->sp_probe_ct = 0; + + switch (spp->sp_state) { + case SPANS_PROBE: + /* + * Interface just came up, update signalling state + */ + spp->sp_state = SPANS_ACTIVE; + break; + + case SPANS_ACTIVE: + break; + + default: + log(LOG_ERR, "spans: received status msg in state %d\n", + spp->sp_state); + } + + /* + * Process the message + */ + spans_host_link(spp, msg->sm_stat_req.streq_es_epoch); +} + + +/* + * Process an open indication or open request + * + * Called when an open indication or open request is received. + * Processing will be based on the state of the requested connection. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the open message + * + * Returns: + * none + * + */ +static void +spans_open_req(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + spans_result result = SPANS_OK; + spans_msg *rsp_msg; + struct spans_vccb *svp = NULL; + struct atm_pif *pip; + spans_vpvc vpvc; + int err = 0, vpi, vci; + Aal_t aal; + Atm_attributes call_attrs; + + ATM_DEBUG2("spans_open_req: spp=0x%x, msg=0x%x\n", spp, msg); + + /* + * See if the connection is new + */ + if (svp = spans_find_conn(spp, &msg->sm_open_req.opreq_conn)) { + /* + * We already have a VCCB that matches the connection in + * the request + */ + vpi = SPANS_EXTRACT_VPI(msg->sm_open_req.opreq_vpvc.vpf_vpvc); + vci = SPANS_EXTRACT_VCI(msg->sm_open_req.opreq_vpvc.vpf_vpvc); + if (msg->sm_open_req.opreq_aal == svp->sv_spans_aal && + (!msg->sm_open_req.opreq_vpvc.vpf_valid || + (vpi == svp->sv_vpi && + vci == svp->sv_vci))) { + /* + * VCCB already exists, process depending on + * state + */ + switch (svp->sv_sstate) { + case SPANS_VC_R_POPEN: + /* I'm still thinking about it */ + return; + case SPANS_VC_OPEN: + /* Retransmit the open_rsp */ + break; + case SPANS_VC_POPEN: + case SPANS_VC_CLOSE: + case SPANS_VC_ABORT: + ATM_DEBUG0("spans_open_req: bad VCCB state\n"); + result = SPANS_FAIL; + break; + } + } else { + /* + * VCCB is for same connection, but other + * parameters don't match + */ + ATM_DEBUG0("spans_open_req: VCCB confusion\n"); + result = SPANS_FAIL; + } + svp = NULL; + goto response; + } + + /* + * Verify that the request is for our ATM addres + */ + if (spans_addr_cmp(spp->sp_addr.address, + &msg->sm_open_req.opreq_conn.con_dst)) { + ATM_DEBUG0("spans_open_req: bad destination\n"); + result = SPANS_BADDEST; + goto response; + } + + /* + * See if we recognize the specified AAL + */ + if (!spans_get_local_aal(msg->sm_open_req.opreq_aal, &aal)) { + ATM_DEBUG0("spans_open_req: bad AAL\n"); + result = SPANS_FAIL; + goto response; + } + + /* + * Should verify that we can handle requested connection QOS + */ + + /* + * Select a VPI/VCI for the new connection + */ + if (msg->sm_open_req.opreq_vpvc.vpf_valid) { + /* + * Requestor asked for a certain VPI/VCI. Make sure we + * aren't already using the pair that was asked for. + */ + vpi = SPANS_EXTRACT_VPI(msg->sm_open_req.opreq_vpvc.vpf_vpvc); + vci = SPANS_EXTRACT_VCI(msg->sm_open_req.opreq_vpvc.vpf_vpvc); + if (spans_find_vpvc(spp, vci, vpi, VCC_IN)) { + ATM_DEBUG0("spans_open_req: VPI, VCI busy\n"); + result = SPANS_NOVPVC; + goto response; + } + vpvc = msg->sm_open_req.opreq_vpvc.vpf_vpvc; + } else { + /* + * Allocate a VPI/VCI for this end of the VCC + */ + vpvc = spans_alloc_vpvc(spp); + if (vpvc == 0) { + ATM_DEBUG0("spans_open_req: no VPI, VCI available\n"); + result = SPANS_NOVPVC; + goto response; + } + } + + /* + * Get a new VCCB for the connection + */ + svp = (struct spans_vccb *)atm_allocate(&spans_vcpool); + if (svp == NULL) { + ATM_DEBUG0("spans_open_req: VCCB pool empty\n"); + result = SPANS_NORSC; + goto response; + } + + /* + * Find the physical interface structure + */ + pip = spp->sp_pif; + + /* + * Fill in the VCCB fields that we can at this point + */ + svp->sv_type = VCC_SVC | VCC_IN; + svp->sv_proto = ATM_SIG_SPANS; + svp->sv_sstate = SPANS_VC_R_POPEN; + svp->sv_ustate = VCCU_POPEN; + svp->sv_pif = pip; + svp->sv_nif = pip->pif_nif; + svp->sv_conn = msg->sm_open_req.opreq_conn; + svp->sv_spans_qos = msg->sm_open_req.opreq_desrsrc; + svp->sv_spans_aal = msg->sm_open_req.opreq_aal; + svp->sv_tstamp = time_second; + + svp->sv_vpi = SPANS_EXTRACT_VPI(vpvc); + svp->sv_vci = SPANS_EXTRACT_VCI(vpvc); + + /* + * Put the VCCB on the SPANS queue + */ + ENQUEUE(svp, struct spans_vccb, sv_sigelem, spp->sp_vccq); + + /* + * Set up the ATM attributes block + */ + KM_ZERO(&call_attrs, sizeof(call_attrs)); + call_attrs.nif = svp->sv_nif; + call_attrs.api = CMAPI_CPCS; + + call_attrs.aal.tag = T_ATM_PRESENT; + call_attrs.aal.type = aal; + switch(aal) { + case ATM_AAL3_4: + call_attrs.aal.v.aal4.forward_max_SDU_size = + ATM_NIF_MTU; + call_attrs.aal.v.aal4.backward_max_SDU_size = + ATM_NIF_MTU; + call_attrs.aal.v.aal4.SSCS_type = + T_ATM_NULL; + call_attrs.aal.v.aal4.mid_low = 0; + call_attrs.aal.v.aal4.mid_high = 1023; + break; + case ATM_AAL5: + call_attrs.aal.v.aal5.forward_max_SDU_size = + ATM_NIF_MTU; + call_attrs.aal.v.aal5.backward_max_SDU_size = + ATM_NIF_MTU; + call_attrs.aal.v.aal5.SSCS_type = + T_ATM_NULL; + break; + } + + call_attrs.traffic.tag = T_ATM_PRESENT; + call_attrs.traffic.v.forward.PCR_high_priority = T_ATM_ABSENT; + call_attrs.traffic.v.forward.PCR_all_traffic = + msg->sm_open_req.opreq_desrsrc.rsc_peak * + 1000 / 53; + call_attrs.traffic.v.forward.SCR_high_priority = T_ATM_ABSENT; + call_attrs.traffic.v.forward.SCR_all_traffic = T_ATM_ABSENT; + call_attrs.traffic.v.forward.MBS_high_priority = T_ATM_ABSENT; + call_attrs.traffic.v.forward.MBS_all_traffic = T_ATM_ABSENT; + call_attrs.traffic.v.forward.tagging = T_NO; + call_attrs.traffic.v.backward.PCR_high_priority = T_ATM_ABSENT; + call_attrs.traffic.v.backward.PCR_all_traffic = + call_attrs.traffic.v.forward.PCR_all_traffic; + call_attrs.traffic.v.backward.SCR_high_priority = T_ATM_ABSENT; + call_attrs.traffic.v.backward.SCR_all_traffic = T_ATM_ABSENT; + call_attrs.traffic.v.backward.MBS_high_priority = T_ATM_ABSENT; + call_attrs.traffic.v.backward.MBS_all_traffic = T_ATM_ABSENT; + call_attrs.traffic.v.backward.tagging = T_NO; + call_attrs.traffic.v.best_effort = T_YES; + + call_attrs.bearer.tag = T_ATM_PRESENT; + call_attrs.bearer.v.bearer_class = T_ATM_CLASS_X; + call_attrs.bearer.v.traffic_type = T_ATM_NULL; + call_attrs.bearer.v.timing_requirements = T_ATM_NULL; + call_attrs.bearer.v.clipping_susceptibility = T_NO; + call_attrs.bearer.v.connection_configuration = T_ATM_1_TO_1; + + + call_attrs.bhli.tag = T_ATM_ABSENT; + call_attrs.blli.tag_l2 = T_ATM_ABSENT; + call_attrs.blli.tag_l3 = T_ATM_ABSENT; + call_attrs.llc.tag = T_ATM_ABSENT; + + call_attrs.called.tag = T_ATM_PRESENT; + spans_addr_copy(&msg->sm_open_req.opreq_conn.con_dst, + call_attrs.called.addr.address); + call_attrs.called.addr.address_format = T_ATM_SPANS_ADDR; + call_attrs.called.addr.address_length = sizeof(spans_addr); + call_attrs.called.subaddr.address_format = T_ATM_ABSENT; + call_attrs.called.subaddr.address_length = 0; + + call_attrs.calling.tag = T_ATM_PRESENT; + spans_addr_copy(&msg->sm_open_req.opreq_conn.con_src, + call_attrs.calling.addr.address); + call_attrs.calling.addr.address_format = T_ATM_SPANS_ADDR; + call_attrs.calling.addr.address_length = sizeof(spans_addr); + call_attrs.calling.subaddr.address_format = T_ATM_ABSENT; + call_attrs.calling.subaddr.address_length = 0; + + call_attrs.qos.tag = T_ATM_PRESENT; + call_attrs.qos.v.coding_standard = T_ATM_NETWORK_CODING; + call_attrs.qos.v.forward.qos_class = T_ATM_QOS_CLASS_0; + call_attrs.qos.v.backward.qos_class = T_ATM_QOS_CLASS_0; + + call_attrs.transit.tag = T_ATM_ABSENT; + call_attrs.cause.tag = T_ATM_ABSENT; + + /* + * Notify the connection manager that it has a new channel + */ + err = atm_cm_incoming((struct vccb *)svp, &call_attrs); + if (err) { + ATM_DEBUG0("spans_open_req: atm_cm_incoming returned error\n"); + result = SPANS_FAIL; + goto response; + } + + /* + * Wait for the connection recipient to issue an accept + */ + return; + +response: + /* + * Clean up the VCCB and the atm_conn block if we got them + */ + if (svp) { + DEQUEUE(svp, struct spans_vccb, sv_sigelem, + spp->sp_vccq); + atm_free(svp); + } + + /* + * Some problem was detected with the request. Send a SPANS + * message rejecting the connection. + */ + rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool); + if (rsp_msg == NULL) + return; + + /* + * Fill out the response + */ + rsp_msg->sm_vers = SPANS_VERS_1_0; + rsp_msg->sm_type = SPANS_OPEN_RSP; + rsp_msg->sm_open_rsp.oprsp_conn = msg->sm_open_req.opreq_conn; + rsp_msg->sm_open_rsp.oprsp_result = result; + rsp_msg->sm_open_rsp.oprsp_vpvc = 0; + + /* + * Send the Open Response + */ + spans_send_msg(spp, rsp_msg); + atm_free(rsp_msg); +} + + +/* + * Process an open response or open confirmation + * + * Called when an open response or open confirmation is received. + * Processing will be based on the state of the requested connection and + * the status returned. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the open response or confirmation message + * + * Returns: + * none + * + */ +static void +spans_open_rsp(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + struct spans_vccb *svp; + + ATM_DEBUG2("spans_open_rsp: spp=0x%x, msg=0x%x\n", spp, msg); + + /* + * Locate the VCCB for the connection + */ + svp = spans_find_conn(spp, &msg->sm_open_rsp.oprsp_conn); + if (svp == NULL) + return; + + /* + * Check the connection state + */ + if ((svp->sv_sstate != SPANS_VC_POPEN && + svp->sv_sstate != SPANS_VC_R_POPEN) || + svp->sv_ustate != VCCU_POPEN) { + ATM_DEBUG2( + "spans_open_rsp: invalid VCCB state, sstate=%d, ustate=%d\n", + svp->sv_sstate, svp->sv_ustate); + return; + } + + /* + * Cancel the retransmission timer + */ + SPANS_VC_CANCEL((struct vccb *) svp); + + /* + * Check the result + */ + switch (msg->sm_open_rsp.oprsp_result) { + + case SPANS_OK: + /* + * Save the assigned VPI and VCI + */ + svp->sv_vpi = SPANS_EXTRACT_VPI(msg->sm_open_rsp.oprsp_vpvc); + svp->sv_vci = SPANS_EXTRACT_VCI(msg->sm_open_rsp.oprsp_vpvc); + + /* + * Update the VCC state and notify the VCC owner + */ + svp->sv_sstate = SPANS_VC_OPEN; + svp->sv_ustate = VCCU_OPEN; + svp->sv_tstamp = time_second; + atm_cm_connected(svp->sv_connvc); + break; + + case SPANS_FAIL: + case SPANS_NOVPVC: + case SPANS_NORSC: + case SPANS_BADDEST: + /* + * Close out the VCCB and notify the user + */ + svp->sv_sstate = SPANS_VC_FREE; + svp->sv_ustate = VCCU_CLOSED; + svp->sv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT; + svp->sv_connvc->cvc_attr.cause.v.coding_standard = + T_ATM_ITU_CODING; + svp->sv_connvc->cvc_attr.cause.v.location = + T_ATM_LOC_USER; + svp->sv_connvc->cvc_attr.cause.v.cause_value = + T_ATM_CAUSE_CALL_REJECTED; + KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics, + sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics)); + atm_cm_cleared(svp->sv_connvc); + break; + + default: + log(LOG_ERR, "spans: unknown result %d in open rsp\n", + msg->sm_open_rsp.oprsp_result); + break; + } +} + + +/* + * Process a close request from the network + * + * Called when a close request, close indication, rclose request, or + * rclose indication is received. Processing will be based on the + * state of the connection. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the close request message + * + * Returns: + * none + * + */ +static void +spans_close_req(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + struct spans_vccb *svp; + spans_result result; + spans_msg *rsp_msg; + u_char outstate; + Atm_connvc *cvp; + + ATM_DEBUG2("spans_close_req: spp=0x%x, msg=0x%x\n", spp, msg); + + /* + * Locate the VCCB for the connection + */ + svp = spans_find_conn(spp, &msg->sm_close_req.clreq_conn); + if (svp == NULL) { + result = SPANS_BADDEST; + goto response; + } + + /* + * Check the connection type + */ + if (!(svp->sv_type & VCC_SVC)) { + result = SPANS_FAIL; + goto response; + } + + /* + * Check the connection state + */ + switch (svp->sv_sstate) { + case SPANS_VC_OPEN: + case SPANS_VC_R_POPEN: + case SPANS_VC_POPEN: + /* + * VCC is open or opening--continue + */ + break; + case SPANS_VC_CLOSE: + case SPANS_VC_FREE: + case SPANS_VC_ABORT: + /* + * We're already closing--give a response, since this + * is probably a retransmission + */ + result = SPANS_OK; + goto response; + case SPANS_VC_NULL: + result = SPANS_FAIL; + goto response; + } + + /* + * Cancel the retransmission timer + */ + SPANS_VC_CANCEL((struct vccb *) svp); + + /* + * Close out the VCCB and notify the user + */ + outstate = svp->sv_sstate; + svp->sv_ustate = VCCU_CLOSED; + svp->sv_sstate = SPANS_VC_FREE; + cvp = svp->sv_connvc; + switch (outstate) { + case SPANS_VC_R_POPEN: + spans_free((struct vccb *)svp); + /* FALLTHRU */ + + case SPANS_VC_POPEN: + case SPANS_VC_OPEN: + cvp->cvc_attr.cause.tag = T_ATM_PRESENT; + cvp->cvc_attr.cause.v.coding_standard = + T_ATM_ITU_CODING; + cvp->cvc_attr.cause.v.location = T_ATM_LOC_USER; + cvp->cvc_attr.cause.v.cause_value = + T_ATM_CAUSE_NORMAL_CALL_CLEARING; + KM_ZERO(cvp->cvc_attr.cause.v.diagnostics, + sizeof(cvp->cvc_attr.cause.v.diagnostics)); + atm_cm_cleared(svp->sv_connvc); + break; + } + + result = SPANS_OK; + +response: + /* + * Respond to the SPANS_CLOSE_IND with a SPANS_CLOSE_RSP + */ + rsp_msg = (spans_msg *)atm_allocate(&spans_msgpool); + if (rsp_msg == NULL) + return; + rsp_msg->sm_vers = SPANS_VERS_1_0; + if (msg->sm_type == SPANS_RCLOSE_REQ || + msg->sm_type == SPANS_RCLOSE_IND) { + rsp_msg->sm_type = SPANS_RCLOSE_RSP; + } else { + rsp_msg->sm_type = SPANS_CLOSE_RSP; + } + rsp_msg->sm_close_rsp.clrsp_conn = msg->sm_close_req.clreq_conn; + rsp_msg->sm_close_rsp.clrsp_result = result; + spans_send_msg(spp, rsp_msg); + atm_free(rsp_msg); +} + + +/* + * Process a close response or close confirmation + * + * Called when an close response or close confirmation is received. + * Processing will be based on the state of the requested connection and + * the returned status. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the close response or confirmation message + * + * Returns: + * none + * + */ +static void +spans_close_rsp(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + struct spans_vccb *svp; + + ATM_DEBUG2("spans_close_rsp: spp=0x%x, msg=0x%x\n", spp, msg); + + /* + * Locate the VCCB for the connection + */ + svp = spans_find_conn(spp, &msg->sm_close_rsp.clrsp_conn); + if (svp == NULL) { + return; + } + + /* + * Check the VCCB state + */ + if (svp->sv_sstate != SPANS_VC_CLOSE) { + return; + } + + /* + * Cancel the retransmission timer + */ + SPANS_VC_CANCEL((struct vccb *) svp); + + /* + * Check the response from the remote end + */ + switch (msg->sm_close_rsp.clrsp_result) { + + case SPANS_OK: + /* + * Mark the VCCB as closed and notify the owner + */ + svp->sv_sstate = SPANS_VC_FREE; + svp->sv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT; + svp->sv_connvc->cvc_attr.cause.v.coding_standard = + T_ATM_ITU_CODING; + svp->sv_connvc->cvc_attr.cause.v.location = + T_ATM_LOC_USER; + svp->sv_connvc->cvc_attr.cause.v.cause_value = + T_ATM_CAUSE_NORMAL_CALL_CLEARING; + KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics, + sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics)); + atm_cm_cleared(svp->sv_connvc); + break; + + case SPANS_NOVPVC: + case SPANS_BADDEST: + case SPANS_FAIL: + case SPANS_NORSC: + /* + * Mark the VCCB as closed and notify the owner + */ + svp->sv_sstate = SPANS_VC_FREE; + svp->sv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT; + svp->sv_connvc->cvc_attr.cause.v.coding_standard = + T_ATM_ITU_CODING; + svp->sv_connvc->cvc_attr.cause.v.location = + T_ATM_LOC_USER; + svp->sv_connvc->cvc_attr.cause.v.cause_value = + T_ATM_CAUSE_UNSPECIFIED_NORMAL; + KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics, + sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics)); + atm_cm_cleared(svp->sv_connvc); + break; + + default: + log(LOG_ERR, "spans: unknown result %d in close rsp\n", + msg->sm_close_rsp.clrsp_result); + break; + } +} + + +/* + * Process a multi request or multi indication + * + * Called when a multi response or multi confirmation is received. We + * don't support multicast channels, so we just reject the request. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the multi request or indication message + * + * Returns: + * none + * + */ +static void +spans_multi_req(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + spans_msg *rsp_msg; + + /* + * Get memory for a SPANS_MULTI_RSP message. + */ + rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool); + if (rsp_msg == NULL) + return; + + /* + * Fill out the response. + */ + rsp_msg->sm_vers = SPANS_VERS_1_0; + rsp_msg->sm_type = SPANS_MULTI_RSP; + rsp_msg->sm_multi_rsp.mursp_conn = msg->sm_multi_req.mureq_conn; + rsp_msg->sm_multi_rsp.mursp_result = SPANS_FAIL; + rsp_msg->sm_multi_rsp.mursp_rsrc = msg->sm_multi_req.mureq_desrsrc; + rsp_msg->sm_multi_rsp.mursp_vpvc = 0; + + /* + * Send the response and free the message. + */ + (void) spans_send_msg(spp, rsp_msg); + atm_free(rsp_msg); +} + + +/* + * Process an add request or add indication + * + * Called when an add response or add confirmation is received. We + * don't support multicast channels, so we just reject the request. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the add request or indication message + * + * Returns: + * none + * + */ +static void +spans_add_req(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + spans_msg *rsp_msg; + + /* + * Get memory for a SPANS_ADD_RSP message. + */ + rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool); + if (rsp_msg == NULL) + return; + + /* + * Fill out the response. + */ + rsp_msg->sm_vers = SPANS_VERS_1_0; + rsp_msg->sm_type = SPANS_ADD_RSP; + rsp_msg->sm_add_rsp.adrsp_conn = msg->sm_add_req.adreq_desconn; + rsp_msg->sm_add_rsp.adrsp_result = SPANS_FAIL; + rsp_msg->sm_add_rsp.adrsp_rsrc.rsc_peak = 0; + rsp_msg->sm_add_rsp.adrsp_rsrc.rsc_mean = 0; + rsp_msg->sm_add_rsp.adrsp_rsrc.rsc_burst = 0; + + /* + * Send the response and free the message. + */ + (void) spans_send_msg(spp, rsp_msg); + atm_free(rsp_msg); +} + + +/* + * Process a join request + * + * Called when an join request is received. We don't support group + * addresses, so we just reject the request. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the join request message + * + * Returns: + * none + * + */ +static void +spans_join_req(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + spans_msg *rsp_msg; + + /* + * Get memory for a SPANS_JOIN_CNF message. + */ + rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool); + if (rsp_msg == NULL) + return; + + /* + * Fill out the response. + */ + rsp_msg->sm_vers = SPANS_VERS_1_0; + rsp_msg->sm_type = SPANS_JOIN_CNF; + spans_addr_copy(&msg->sm_join_req.jnreq_addr, + &rsp_msg->sm_join_cnf.jncnf_addr); + rsp_msg->sm_join_cnf.jncnf_result = SPANS_FAIL; + + /* + * Send the response and free the message. + */ + (void) spans_send_msg(spp, rsp_msg); + atm_free(rsp_msg); +} + + +/* + * Process a leave request + * + * Called when an leave request is received. We don't support group + * addresses, so we just reject the request. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the leave request message + * + * Returns: + * none + * + */ +static void +spans_leave_req(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + spans_msg *rsp_msg; + + /* + * Get memory for a SPANS_LEAVE_CNF message. + */ + rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool); + if (rsp_msg == NULL) + return; + + /* + * Fill out the response. + */ + rsp_msg->sm_vers = SPANS_VERS_1_0; + rsp_msg->sm_type = SPANS_LEAVE_CNF; + spans_addr_copy(&msg->sm_leave_req.lvreq_addr, + &rsp_msg->sm_leave_cnf.lvcnf_addr); + rsp_msg->sm_leave_cnf.lvcnf_result = SPANS_FAIL; + + /* + * Send the response and free the message. + */ + (void) spans_send_msg(spp, rsp_msg); + atm_free(rsp_msg); +} + + +/* + * Process a VCI range indication + * + * Called when a VCI range indication is received. Adjust the VCI + * bounds if they have changed. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the VCI range indication message + * + * Returns: + * none + * + */ +static void +spans_vcir_ind(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + /* + * Adjust the limits if they have changed + */ + if (msg->sm_vcir_ind.vrind_min != spp->sp_min_vci) { + spp->sp_min_vci = + (msg->sm_vcir_ind.vrind_min < + SPANS_MIN_VCI ? + SPANS_MIN_VCI : + msg->sm_vcir_ind.vrind_min); + } + if (msg->sm_vcir_ind.vrind_max != spp->sp_max_vci) { + spp->sp_max_vci = + (msg->sm_vcir_ind.vrind_max > + SPANS_MAX_VCI ? + SPANS_MAX_VCI : + msg->sm_vcir_ind.vrind_max); + } +} + + +/* + * Process a query request + * + * Called when a query request is received. Respond with the + * appropriate query response. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * msg pointer to the VCI range indication message + * + * Returns: + * none + * + */ +static void +spans_query_req(spp, msg) + struct spans *spp; + spans_msg *msg; +{ + struct spans_vccb *svp = NULL; + spans_msg *rsp_msg; + + ATM_DEBUG1("spans_query_req: msg=0x%x\n", msg); + + /* + * Ignore an end-to-end query + */ + if (msg->sm_query_req.qyreq_type == SPANS_QUERY_END_TO_END) { + return; + } + + /* + * Get memory for a SPANS_QUERY_RSP message. + */ + rsp_msg = (spans_msg *) atm_allocate(&spans_msgpool); + if (rsp_msg == NULL) + return; + + /* + * Fill out the response. + */ + rsp_msg->sm_vers = SPANS_VERS_1_0; + rsp_msg->sm_type = SPANS_QUERY_RSP; + rsp_msg->sm_query_rsp.qyrsp_conn = msg->sm_query_req.qyreq_conn; + rsp_msg->sm_query_rsp.qyrsp_type = msg->sm_query_req.qyreq_type; + rsp_msg->sm_query_rsp.qyrsp_data = 0; + + /* + * Get the state of the requested connection + */ + svp = spans_find_conn(spp, &msg->sm_query_req.qyreq_conn); + if (svp) { + switch(svp->sv_sstate) { + case SPANS_VC_NULL: + case SPANS_VC_FREE: + rsp_msg->sm_query_rsp.qyrsp_state = + SPANS_CONN_CLOSED; + break; + case SPANS_VC_OPEN: + rsp_msg->sm_query_rsp.qyrsp_state = + SPANS_CONN_OPEN; + break; + case SPANS_VC_POPEN: + case SPANS_VC_R_POPEN: + rsp_msg->sm_query_rsp.qyrsp_state = + SPANS_CONN_OPEN_PEND; + break; + case SPANS_VC_CLOSE: + case SPANS_VC_ABORT: + rsp_msg->sm_query_rsp.qyrsp_state = + SPANS_CONN_CLOSE_PEND; + break; + case SPANS_VC_ACTIVE: + case SPANS_VC_ACT_DOWN: + /* + * VCCB is for a PVC (shouldn't happen) + */ + atm_free(rsp_msg); + return; + } + } else { + /* + * No VCCB found--connection doesn't exist + */ + rsp_msg->sm_query_rsp.qyrsp_state = SPANS_CONN_CLOSED; + } + + /* + * Send the response and free the message. + */ + (void) spans_send_msg(spp, rsp_msg); + atm_free(rsp_msg); +} + + +/* + * Process a SPANS signalling message + * + * Called when a SPANS message is received. The message is converted + * into internal format with XDR and decoded by calling the appropriate + * mesage handling routine. Unrecognized and unexpected messages are + * logged. + * + * Arguments: + * spp pointer to SPANS protocol instance block + * m pointer to a buffer chain containing the SPANS message + * + * Returns: + * none + * + */ +void +spans_rcv_msg(spp, m) + struct spans *spp; + KBuffer *m; +{ + XDR xdrs; + spans_msg *msg; + + /* + * Get storage for the message + */ + msg = (spans_msg *)atm_allocate(&spans_msgpool); + if (msg == NULL) { + return; + } + + /* + * Convert the message from network order to internal format + */ + xdrmbuf_init(&xdrs, m, XDR_DECODE); + if (!xdr_spans_msg(&xdrs, msg)) { + log(LOG_ERR, "spans_rcv_msg: XDR decode failed\n"); + spans_dump_buffer(m); + goto done; + } + +#ifdef NOTDEF + /* + * Debug--print some information about the message + */ + if (msg->sm_type != SPANS_STAT_REQ && + msg->sm_type != SPANS_STAT_IND && + msg->sm_type != SPANS_STAT_RSP) { + printf("spans_rcv_msg: got "); + spans_print_msg(msg); + } +#endif + + /* + * Verify the message sm_vers + */ + if (msg->sm_vers != SPANS_VERS_1_0) { + log(LOG_ERR, "spans: invalid message version 0x%x\n", + msg->sm_vers); + } + + /* + * Ignore the message if SPANS isn't up yet + */ + if (spp->sp_state != SPANS_ACTIVE && + (spp->sp_state != SPANS_PROBE || + (msg->sm_type != SPANS_STAT_REQ && + msg->sm_type != SPANS_STAT_RSP && + msg->sm_type != SPANS_STAT_IND))) { + goto done; + } + + /* + * Process the message based on its type + */ + switch(msg->sm_type) { + case SPANS_STAT_REQ: + spans_status_ind(spp, msg); + break; + case SPANS_STAT_IND: + spans_status_ind(spp, msg); + break; + case SPANS_STAT_RSP: + spans_status_rsp(spp, msg); + break; + case SPANS_OPEN_REQ: + spans_open_req(spp, msg); + break; + case SPANS_OPEN_IND: + spans_open_req(spp, msg); + break; + case SPANS_OPEN_RSP: + spans_open_rsp(spp, msg); + break; + case SPANS_OPEN_CNF: + spans_open_rsp(spp, msg); + break; + case SPANS_CLOSE_REQ: + spans_close_req(spp, msg); + break; + case SPANS_CLOSE_IND: + spans_close_req(spp, msg); + break; + case SPANS_CLOSE_RSP: + spans_close_rsp(spp, msg); + break; + case SPANS_CLOSE_CNF: + spans_close_rsp(spp, msg); + break; + case SPANS_RCLOSE_REQ: + spans_close_req(spp, msg); + break; + case SPANS_RCLOSE_IND: + spans_close_req(spp, msg); + break; + case SPANS_RCLOSE_RSP: + spans_close_rsp(spp, msg); + break; + case SPANS_RCLOSE_CNF: + spans_close_rsp(spp, msg); + break; + case SPANS_MULTI_REQ: + spans_multi_req(spp, msg); + break; + case SPANS_MULTI_IND: + spans_multi_req(spp, msg); + break; + case SPANS_MULTI_RSP: + log(LOG_ERR, + "spans: unexpected message (multi_rsp)\n"); + break; + case SPANS_MULTI_CNF: + log(LOG_ERR, + "spans: unexpected message (multi_conf)\n"); + break; + case SPANS_ADD_REQ: + spans_add_req(spp, msg); + break; + case SPANS_ADD_IND: + spans_add_req(spp, msg); + break; + case SPANS_ADD_RSP: + log(LOG_ERR, + "spans: unexpected message (add_rsp)\n"); + break; + case SPANS_ADD_CNF: + log(LOG_ERR, "spans: unexpected message (add_conf)\n"); + break; + case SPANS_JOIN_REQ: + spans_join_req(spp, msg); + break; + case SPANS_JOIN_CNF: + log(LOG_ERR, "spans: unexpected message (join_conf)\n"); + break; + case SPANS_LEAVE_REQ: + spans_leave_req(spp, msg); + break; + case SPANS_LEAVE_CNF: + log(LOG_ERR, + "spans: unexpected message (leave_conf)\n"); + break; + case SPANS_VCIR_IND: + spans_vcir_ind(spp, msg); + break; + case SPANS_QUERY_REQ: + spans_query_req(spp, msg); + break; + case SPANS_QUERY_RSP: + log(LOG_ERR, + "spans: unexpected message (query_rsp)\n"); + break; + default: + log(LOG_ERR, "spans: unknown SPANS message type %d\n", + msg->sm_type); + } + +done: + /* + * Free the incoming message (both buffer and internal format) if + * necessary. + */ + if (msg) + atm_free(msg); + if (m) + KB_FREEALL(m); +} diff --git a/sys/netatm/spans/spans_print.c b/sys/netatm/spans/spans_print.c new file mode 100644 index 0000000..60dc670 --- /dev/null +++ b/sys/netatm/spans/spans_print.c @@ -0,0 +1,1062 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: spans_print.c,v 1.4 1997/05/06 22:17:11 mks Exp $ + * + */ + +/* + * SPANS Signalling Manager + * --------------------------- + * + * SPANS Print Routines. + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: spans_print.c,v 1.4 1997/05/06 22:17:11 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include "spans_xdr.h" +#include <netatm/spans/spans_var.h> + +/* + * If LONGPRINT is defined, every field of the SPANS message will be + * printed. If not, a shorter summary (useful for debugging without + * swamping the console) is printed. + */ +/* #define LONGPRINT */ + +/* + * Local functions + */ +static void inc_indent __P((void)); +static void dec_indent __P((void)); +static void spans_aal_str __P((spans_aal *, char *)); +static void spans_result_str __P((spans_result *, char *)); +static void spans_msgtype_str __P((spans_msgtype *, char *)); +static void spans_query_type_str __P((spans_query_type *, char *)); +static void spans_state_str __P((spans_query_type *, char *)); +static void spans_print_version __P((spans_version *)); +static void spans_print_vpvc __P((spans_vpvc *)); +static void spans_print_vpvc_pref __P((spans_vpvc_pref *)); +static void spans_print_addr __P((spans_addr *)); +static void spans_print_sap __P((spans_sap *)); +static void spans_print_atm_conn __P((spans_atm_conn *)); +static void spans_print_resrc __P((spans_resrc *)); +static void spans_print_aal __P((spans_aal *)); +static void spans_print_result __P((spans_result *)); +static void spans_print_msgtype __P((spans_msgtype *)); +static void spans_print_parm_stat_req __P((spans_parm_stat_req *)); +static void spans_print_parm_stat_ind __P((spans_parm_stat_ind *)); +static void spans_print_parm_stat_rsp __P((spans_parm_stat_rsp *)); +static void spans_print_parm_open_req __P((spans_parm_open_req *)); +static void spans_print_parm_open_ind __P((spans_parm_open_ind *)); +static void spans_print_parm_open_rsp __P((spans_parm_open_rsp *)); +static void spans_print_parm_open_cnf __P((spans_parm_open_cnf *)); +static void spans_print_parm_close_req __P((spans_parm_close_req *)); +static void spans_print_parm_close_ind __P((spans_parm_close_ind *)); +static void spans_print_parm_close_rsp __P((spans_parm_close_rsp *)); +static void spans_print_parm_close_cnf __P((spans_parm_close_cnf *)); +static void spans_print_parm_rclose_req __P((spans_parm_rclose_req *)); +static void spans_print_parm_rclose_ind __P((spans_parm_rclose_ind *)); +static void spans_print_parm_rclose_rsp __P((spans_parm_rclose_rsp *)); +static void spans_print_parm_rclose_cnf __P((spans_parm_rclose_cnf *)); +static void spans_print_parm_multi_req __P((spans_parm_multi_req *)); +static void spans_print_parm_multi_ind __P((spans_parm_multi_ind *)); +static void spans_print_parm_multi_rsp __P((spans_parm_multi_rsp *)); +static void spans_print_parm_multi_cnf __P((spans_parm_multi_cnf *)); +static void spans_print_parm_add_req __P((spans_parm_add_req *)); +static void spans_print_parm_add_ind __P((spans_parm_add_ind *)); +static void spans_print_parm_add_rsp __P((spans_parm_add_rsp *)); +static void spans_print_parm_add_cnf __P((spans_parm_add_cnf *)); +static void spans_print_parm_join_req __P((spans_parm_join_req *)); +static void spans_print_parm_join_cnf __P((spans_parm_join_cnf *)); +static void spans_print_parm_leave_req __P((spans_parm_leave_req *)); +static void spans_print_parm_leave_cnf __P((spans_parm_leave_cnf *)); +static void spans_print_parm_vcir_ind __P((spans_parm_vcir_ind *)); +static void spans_print_parm_query_req __P((spans_parm_query_req *)); +static void spans_print_parm_query_rsp __P((spans_parm_query_rsp *)); +static void spans_print_msgbody __P((spans_msgbody *)); + + +/* + * Local variables + */ +#define MAX_INDENT 10 +#define INIT_INDENT &indent_str[MAX_INDENT] +static char *spans_indent; +static char indent_str[11] = " "; + +static void +inc_indent() +{ + if (spans_indent != &indent_str[0]) { + *spans_indent--; + } +} + +static void +dec_indent() +{ + if (spans_indent != INIT_INDENT) { + *spans_indent++; + } +} + +static void +spans_aal_str(objp, dest) + spans_aal *objp; + char *dest; +{ + static char *aal_names[] = { + "SPANS_AAL0", + "SPANS_AAL1", + "SPANS_AAL2", + "SPANS_AAL3", + "SPANS_AAL4", + "SPANS_AAL5" + }; + + if (*objp < SPANS_AAL0 || *objp > SPANS_AAL5) { + sprintf(dest, "Invalid (%d)", (int)*objp); + } else { + sprintf(dest, "%s (%d)", aal_names[(int)*objp], + (int)*objp); + } +} + +static void +spans_result_str(objp, dest) + spans_result *objp; + char *dest; +{ + static char *result_names[] = { + "SPANS_OK", + "SPANS_FAIL", + "SPANS_NOVPVC", + "SPANS_NORSC", + "SPANS_BADDEST" + }; + + if (*objp < SPANS_OK || *objp > SPANS_BADDEST) { + sprintf(dest, "Invalid (%d)", (int)*objp); + } else { + sprintf(dest, "%s (%d)", + result_names[(int)*objp], (int)*objp); + } +} + +static void +spans_msgtype_str(objp, dest) + spans_msgtype *objp; + char *dest; +{ + int i; + + static struct { + spans_msgtype type; + char *name; + } msgtype_names[] = { + { SPANS_STAT_REQ, "SPANS_STAT_REQ" }, + { SPANS_STAT_IND, "SPANS_STAT_IND" }, + { SPANS_STAT_RSP, "SPANS_STAT_RSP" }, + { SPANS_OPEN_REQ, "SPANS_OPEN_REQ" }, + { SPANS_OPEN_IND, "SPANS_OPEN_IND" }, + { SPANS_OPEN_RSP, "SPANS_OPEN_RSP" }, + { SPANS_OPEN_CNF, "SPANS_OPEN_CNF" }, + { SPANS_CLOSE_REQ, "SPANS_CLOSE_REQ" }, + { SPANS_CLOSE_IND, "SPANS_CLOSE_IND" }, + { SPANS_CLOSE_RSP, "SPANS_CLOSE_RSP" }, + { SPANS_CLOSE_CNF, "SPANS_CLOSE_CNF" }, + { SPANS_RCLOSE_REQ, "SPANS_RCLOSE_REQ" }, + { SPANS_RCLOSE_IND, "SPANS_RCLOSE_IND" }, + { SPANS_RCLOSE_RSP, "SPANS_RCLOSE_RSP" }, + { SPANS_RCLOSE_CNF, "SPANS_RCLOSE_CNF" }, + { SPANS_MULTI_REQ, "SPANS_MULTI_REQ" }, + { SPANS_MULTI_IND, "SPANS_MULTI_IND" }, + { SPANS_MULTI_RSP, "SPANS_MULTI_RSP" }, + { SPANS_MULTI_CNF, "SPANS_MULTI_CNF" }, + { SPANS_ADD_REQ, "SPANS_ADD_REQ" }, + { SPANS_ADD_IND, "SPANS_ADD_IND" }, + { SPANS_ADD_RSP, "SPANS_ADD_RSP" }, + { SPANS_ADD_CNF, "SPANS_ADD_CNF" }, + { SPANS_JOIN_REQ, "SPANS_JOIN_REQ" }, + { SPANS_JOIN_CNF, "SPANS_JOIN_CNF" }, + { SPANS_LEAVE_REQ, "SPANS_LEAVE_REQ" }, + { SPANS_LEAVE_CNF, "SPANS_LEAVE_CNF" }, + { SPANS_VCIR_IND, "SPANS_VCIR_IND" }, + { SPANS_QUERY_REQ, "SPANS_QUERY_REQ" }, + { SPANS_QUERY_RSP, "SPANS_QUERY_RSP" }, + { 0, (char *) 0 } + }; + + /* + * Search the name table for the specified type + */ + for (i=0; msgtype_names[i].name; i++) { + if (*objp == msgtype_names[i].type) { + sprintf(dest, "%s (%d)", + msgtype_names[i].name, + (int)*objp); + return; + } + } + + /* + * Type was not found--return an error indicator + */ + sprintf(dest, "Invalid (%d)", (int)*objp); +} + +static void +spans_query_type_str(objp, dest) + spans_query_type *objp; + char *dest; +{ + static char *query_names[] = { + "SPANS_QUERY_NORMAL", + "SPANS_QUERY_DEBUG", + "SPANS_QUERY_END_TO_END" + }; + + if (*objp < SPANS_QUERY_NORMAL || + *objp > SPANS_QUERY_END_TO_END) { + sprintf(dest, "Invalid (%d)", (int)*objp); + } else { + sprintf(dest, "%s (%d)", query_names[(int)*objp], + (int)*objp); + } +} + +static void +spans_state_str(objp, dest) + spans_query_type *objp; + char *dest; +{ + static char *state_names[] = { + "SPANS_CONN_OPEN", + "SPANS_CONN_OPEN_PEND", + "SPANS_CONN_CLOSE_PEND", + "SPANS_CONN_CLOSED" + }; + + if (*objp < SPANS_CONN_OPEN || *objp > SPANS_CONN_CLOSED) { + sprintf(dest, "Invalid (%d)", (int)*objp); + } else { + sprintf(dest, "%s (%d)", state_names[(int)*objp], + (int)*objp); + } +} + +#ifdef LONGPRINT + +static void +spans_print_version(objp) + spans_version *objp; +{ + printf("%sspans_version 0x%x\n", spans_indent, *objp); +} + +static void +spans_print_vpvc(objp) + spans_vpvc *objp; +{ + printf("%sVP/VC %d/%d\n", spans_indent, + SPANS_EXTRACT_VPI(*objp), + SPANS_EXTRACT_VCI(*objp)); +} + +static void +spans_print_vpvc_pref(objp) + spans_vpvc_pref *objp; +{ + printf("%sspans_vpvc_pref\n", spans_indent); + inc_indent(); + printf("%s%s\n", spans_indent, + (objp->vpf_valid ? "Valid" : "Not valid")); + spans_print_vpvc(&objp->vpf_vpvc); + dec_indent(); +} + +static void +spans_print_addr(objp) + spans_addr *objp; +{ + char addr_str[80]; + + strncpy(addr_str, spans_addr_print(objp), sizeof(addr_str)); + printf("%sspans_addr %s\n", spans_indent, addr_str); +} + +static void +spans_print_sap(objp) + spans_sap *objp; +{ + printf("%sSAP %d\n", spans_indent, *objp); +} + +static void +spans_print_atm_conn(objp) + spans_atm_conn *objp; +{ + printf("%sspans_atm_conn\n", spans_indent); + inc_indent(); + spans_print_addr(&objp->con_dst); + spans_print_addr(&objp->con_src); + spans_print_sap(&objp->con_dsap); + spans_print_sap(&objp->con_ssap); + dec_indent(); +} + +static void +spans_print_resrc(objp) + spans_resrc *objp; +{ + printf("%sspans_resrc\n", spans_indent); + inc_indent(); + printf("%srsc_peak %d\n", spans_indent, objp->rsc_peak); + printf("%srsc_mean %d\n", spans_indent, objp->rsc_mean); + printf("%srsc_burst %d\n", spans_indent, objp->rsc_burst); + dec_indent(); +} + +static void +spans_print_aal(objp) + spans_aal *objp; +{ + char aal_str[80]; + + spans_aal_str(objp, aal_str); + printf("%sspans_aal %s\n", spans_indent, aal_str); +} + +static void +spans_print_result(objp) + spans_result *objp; +{ + char result_str[80]; + + spans_result_str(objp, result_str); + printf("%sspans_result %s\n", spans_indent, result_str); +} + +static void +spans_print_msgtype(objp) + spans_msgtype *objp; +{ + char msgtype_str[80]; + + spans_msgtype_str(objp, msgtype_str); + printf("%sspans_msgtype %s\n", spans_indent, msgtype_str); +} + +static void +spans_print_parm_stat_req(objp) + spans_parm_stat_req *objp; +{ + printf("%sspans_parm_stat_req\n", spans_indent); + inc_indent(); + printf("%sstreq_es_epoch %d\n", spans_indent, + objp->streq_es_epoch); + dec_indent(); +} + +static void +spans_print_parm_stat_ind(objp) + spans_parm_stat_ind *objp; +{ + printf("%sspans_parm_stat_ind\n", spans_indent); + inc_indent(); + printf("%sstind_sw_epoch %d\n", spans_indent, + objp->stind_sw_epoch); + spans_print_addr(&objp->stind_es_addr); + spans_print_addr(&objp->stind_sw_addr); + dec_indent(); +} + +static void +spans_print_parm_stat_rsp(objp) + spans_parm_stat_rsp *objp; +{ + printf("%sspans_parm_stat_rsp\n", spans_indent); + inc_indent(); + printf("%sstrsp_es_epoch %d\n", spans_indent, + objp->strsp_es_epoch); + spans_print_addr(&objp->strsp_es_addr); + dec_indent(); +} + +static void +spans_print_parm_open_req(objp) + spans_parm_open_req *objp; +{ + printf("%sspans_parm_open_req\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->opreq_conn); + spans_print_aal(&objp->opreq_aal); + spans_print_resrc(&objp->opreq_desrsrc); + spans_print_resrc(&objp->opreq_minrsrc); + spans_print_vpvc_pref(&objp->opreq_vpvc); + dec_indent(); +} + +static void +spans_print_parm_open_ind(objp) + spans_parm_open_ind *objp; +{ + printf("%sspans_parm_open_ind\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->opind_conn); + spans_print_aal(&objp->opind_aal); + spans_print_resrc(&objp->opind_desrsrc); + spans_print_resrc(&objp->opind_minrsrc); + spans_print_vpvc_pref(&objp->opind_vpvc); + dec_indent(); +} + +static void +spans_print_parm_open_rsp(objp) + spans_parm_open_rsp *objp; +{ + printf("%sspans_parm_open_rsp\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->oprsp_conn); + spans_print_result(&objp->oprsp_result); + spans_print_resrc(&objp->oprsp_rsrc); + spans_print_vpvc(&objp->oprsp_vpvc); + dec_indent(); +} + +static void +spans_print_parm_open_cnf(objp) + spans_parm_open_cnf *objp; +{ + printf("%sspans_parm_open_cnf\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->opcnf_conn); + spans_print_result(&objp->opcnf_result); + spans_print_resrc(&objp->opcnf_rsrc); + spans_print_vpvc(&objp->opcnf_vpvc); + dec_indent(); +} + +static void +spans_print_parm_close_req(objp) + spans_parm_close_req *objp; +{ + printf("%sspans_parm_close_req\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->clreq_conn); + dec_indent(); +} + +static void +spans_print_parm_close_ind(objp) + spans_parm_close_ind *objp; +{ + printf("%sspans_parm_close_ind\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->clind_conn); + dec_indent(); +} + +static void +spans_print_parm_close_rsp(objp) + spans_parm_close_rsp *objp; +{ + printf("%sspans_parm_close_rsp\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->clrsp_conn); + spans_print_result(&objp->clrsp_result); + dec_indent(); +} + +static void +spans_print_parm_close_cnf(objp) + spans_parm_close_cnf *objp; +{ + printf("%sspans_parm_close_cnf\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->clcnf_conn); + spans_print_result(&objp->clcnf_result); + dec_indent(); +} + +static void +spans_print_parm_rclose_req(objp) + spans_parm_rclose_req *objp; +{ + printf("%sspans_parm_rclose_req\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->rcreq_conn); + dec_indent(); +} + +static void +spans_print_parm_rclose_ind(objp) + spans_parm_rclose_ind *objp; +{ + printf("%sspans_parm_rclose_ind\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->rcind_conn); + dec_indent(); +} + +static void +spans_print_parm_rclose_rsp(objp) + spans_parm_rclose_rsp *objp; +{ + printf("%sspans_parm_rclose_rsp\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->rcrsp_conn); + spans_print_result(&objp->rcrsp_result); + dec_indent(); +} + +static void +spans_print_parm_rclose_cnf(objp) + spans_parm_rclose_cnf *objp; +{ + printf("%sspans_parm_rclose_cnf\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->rccnf_conn); + spans_print_result(&objp->rccnf_result); + dec_indent(); +} + +static void +spans_print_parm_multi_req(objp) + spans_parm_multi_req *objp; +{ + printf("%sspans_parm_multi_req\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->mureq_conn); + spans_print_aal(&objp->mureq_aal); + spans_print_resrc(&objp->mureq_desrsrc); + spans_print_resrc(&objp->mureq_minrsrc); + spans_print_vpvc(&objp->mureq_vpvc); + dec_indent(); +} + +static void +spans_print_parm_multi_ind(objp) + spans_parm_multi_ind *objp; +{ + printf("%sspans_parm_multi_ind\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->muind_conn); + spans_print_aal(&objp->muind_aal); + spans_print_resrc(&objp->muind_desrsrc); + spans_print_resrc(&objp->muind_minrsrc); + spans_print_vpvc(&objp->muind_vpvc); + dec_indent(); +} + +static void +spans_print_parm_multi_rsp(objp) + spans_parm_multi_rsp *objp; +{ + printf("%sspans_parm_multi_rsp\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->mursp_conn); + spans_print_result(&objp->mursp_result); + spans_print_resrc(&objp->mursp_rsrc); + spans_print_vpvc(&objp->mursp_vpvc); + dec_indent(); +} + +static void +spans_print_parm_multi_cnf(objp) + spans_parm_multi_cnf *objp; +{ + printf("%sspans_parm_multi_cnf\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->mucnf_conn); + spans_print_result(&objp->mucnf_result); + spans_print_resrc(&objp->mucnf_rsrc); + spans_print_vpvc(&objp->mucnf_vpvc); + dec_indent(); +} + +static void +spans_print_parm_add_req(objp) + spans_parm_add_req *objp; +{ + printf("%sspans_parm_add_req\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->adreq_desconn); + spans_print_atm_conn(&objp->adreq_xstconn); + dec_indent(); +} + +static void +spans_print_parm_add_ind(objp) + spans_parm_add_ind *objp; +{ + printf("%sspans_parm_add_ind\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->adind_desconn); + spans_print_atm_conn(&objp->adind_xstconn); + dec_indent(); +} + +static void +spans_print_parm_add_rsp(objp) + spans_parm_add_rsp *objp; +{ + printf("%sspans_parm_add_rsp\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->adrsp_conn); + spans_print_result(&objp->adrsp_result); + spans_print_resrc(&objp->adrsp_rsrc); + dec_indent(); +} + +static void +spans_print_parm_add_cnf(objp) + spans_parm_add_cnf *objp; +{ + printf("%sspans_parm_add_cnf\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->adcnf_conn); + spans_print_result(&objp->adcnf_result); + spans_print_resrc(&objp->adcnf_rsrc); + dec_indent(); +} + +static void +spans_print_parm_join_req(objp) + spans_parm_join_req *objp; +{ + printf("%sspans_parm_join_req\n", spans_indent); + inc_indent(); + spans_print_addr(&objp->jnreq_addr); + dec_indent(); +} + +static void +spans_print_parm_join_cnf(objp) + spans_parm_join_cnf *objp; +{ + printf("%sspans_print_parm_join_cnf\n", spans_indent); + inc_indent(); + spans_print_addr(&objp->jncnf_addr); + spans_print_result(&objp->jncnf_result); + dec_indent(); +} + +static void +spans_print_parm_leave_req(objp) + spans_parm_leave_req *objp; +{ + printf("%sspans_print_parm_leave_req\n", spans_indent); + inc_indent(); + spans_print_addr(&objp->lvreq_addr); + dec_indent(); +} + +static void +spans_print_parm_leave_cnf(objp) + spans_parm_leave_cnf *objp; +{ + printf("%sspans_parm_leave_cnf\n", spans_indent); + inc_indent(); + spans_print_addr(&objp->lvcnf_addr); + spans_print_result(&objp->lvcnf_result); + dec_indent(); +} + +static void +spans_print_parm_vcir_ind(objp) + spans_parm_vcir_ind *objp; +{ + printf("%sspans_parm_vcir_ind\n", spans_indent); + inc_indent(); + printf("%svrind_min %d\n", spans_indent, objp->vrind_min); + printf("%svrind_max %d\n", spans_indent, objp->vrind_max); + dec_indent(); +} + +static void +spans_print_parm_query_req(objp) + spans_parm_query_req *objp; +{ + char query_type_str[80]; + + printf("%sspans_parm_query_req\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->qyreq_conn); + spans_query_type_str(&objp->qyreq_type, query_type_str); + printf("%sqyreq_type %s\n", spans_indent, query_type_str); + dec_indent(); +} + +static void +spans_print_parm_query_rsp(objp) + spans_parm_query_rsp *objp; +{ + char query_type_str[80], state_type_str[80]; + + printf("%sspans_parm_query_rsp\n", spans_indent); + inc_indent(); + spans_print_atm_conn(&objp->qyrsp_conn); + spans_query_type_str(&objp->qyrsp_type, query_type_str); + printf("%sqyrsp_type %s\n", spans_indent, query_type_str); + spans_state_str(&objp->qyrsp_state, state_type_str); + printf("%sqyrsp_state %s\n", spans_indent, state_type_str); + printf("%sqyrsp_data 0x%x\n", spans_indent, + objp->qyrsp_data); + dec_indent(); +} + +static void +spans_print_msgbody(objp) + spans_msgbody *objp; +{ + printf("%sspans_msgbody\n", spans_indent); + inc_indent(); + spans_print_msgtype(&objp->mb_type); + switch (objp->mb_type) { + case SPANS_STAT_REQ: + spans_print_parm_stat_req(&objp->spans_msgbody_u.mb_stat_req); + break; + case SPANS_STAT_IND: + spans_print_parm_stat_ind(&objp->spans_msgbody_u.mb_stat_ind); + break; + case SPANS_STAT_RSP: + spans_print_parm_stat_rsp(&objp->spans_msgbody_u.mb_stat_rsp); + break; + case SPANS_OPEN_REQ: + spans_print_parm_open_req(&objp->spans_msgbody_u.mb_open_req); + break; + case SPANS_OPEN_IND: + spans_print_parm_open_ind(&objp->spans_msgbody_u.mb_open_ind); + break; + case SPANS_OPEN_RSP: + spans_print_parm_open_rsp(&objp->spans_msgbody_u.mb_open_rsp); + break; + case SPANS_OPEN_CNF: + spans_print_parm_open_cnf(&objp->spans_msgbody_u.mb_open_cnf); + break; + case SPANS_CLOSE_REQ: + spans_print_parm_close_req(&objp->spans_msgbody_u.mb_close_req); + break; + case SPANS_CLOSE_IND: + spans_print_parm_close_ind(&objp->spans_msgbody_u.mb_close_ind); + break; + case SPANS_CLOSE_RSP: + spans_print_parm_close_rsp(&objp->spans_msgbody_u.mb_close_rsp); + break; + case SPANS_CLOSE_CNF: + spans_print_parm_close_cnf(&objp->spans_msgbody_u.mb_close_cnf); + break; + case SPANS_RCLOSE_REQ: + spans_print_parm_rclose_req(&objp->spans_msgbody_u.mb_rclose_req); + break; + case SPANS_RCLOSE_IND: + spans_print_parm_rclose_ind(&objp->spans_msgbody_u.mb_rclose_ind); + break; + case SPANS_RCLOSE_RSP: + spans_print_parm_rclose_rsp(&objp->spans_msgbody_u.mb_rclose_rsp); + break; + case SPANS_RCLOSE_CNF: + spans_print_parm_rclose_cnf(&objp->spans_msgbody_u.mb_rclose_cnf); + break; + case SPANS_MULTI_REQ: + spans_print_parm_multi_req(&objp->spans_msgbody_u.mb_multi_req); + break; + case SPANS_MULTI_IND: + spans_print_parm_multi_ind(&objp->spans_msgbody_u.mb_multi_ind); + break; + case SPANS_MULTI_RSP: + spans_print_parm_multi_rsp(&objp->spans_msgbody_u.mb_multi_rsp); + break; + case SPANS_MULTI_CNF: + spans_print_parm_multi_cnf(&objp->spans_msgbody_u.mb_multi_cnf); + break; + case SPANS_ADD_REQ: + spans_print_parm_add_req(&objp->spans_msgbody_u.mb_add_req); + break; + case SPANS_ADD_IND: + spans_print_parm_add_ind(&objp->spans_msgbody_u.mb_add_ind); + break; + case SPANS_ADD_RSP: + spans_print_parm_add_rsp(&objp->spans_msgbody_u.mb_add_rsp); + break; + case SPANS_ADD_CNF: + spans_print_parm_add_cnf(&objp->spans_msgbody_u.mb_add_cnf); + break; + case SPANS_JOIN_REQ: + spans_print_parm_join_req(&objp->spans_msgbody_u.mb_join_req); + break; + case SPANS_JOIN_CNF: + spans_print_parm_join_cnf(&objp->spans_msgbody_u.mb_join_cnf); + break; + case SPANS_LEAVE_REQ: + spans_print_parm_leave_req(&objp->spans_msgbody_u.mb_leave_req); + break; + case SPANS_LEAVE_CNF: + spans_print_parm_leave_cnf(&objp->spans_msgbody_u.mb_leave_cnf); + break; + case SPANS_VCIR_IND: + spans_print_parm_vcir_ind(&objp->spans_msgbody_u.mb_vcir_ind); + break; + case SPANS_QUERY_REQ: + spans_print_parm_query_req(&objp->spans_msgbody_u.mb_query_req); + break; + case SPANS_QUERY_RSP: + spans_print_parm_query_rsp(&objp->spans_msgbody_u.mb_query_rsp); + break; + } + dec_indent(); +} + +void +spans_print_msg(objp) + spans_msg *objp; +{ + spans_indent = INIT_INDENT; + printf("%sspans_msg\n", spans_indent); + inc_indent(); + spans_print_version(&objp->sm_vers); + spans_print_msgbody(&objp->sm_body); + dec_indent(); +} + +#else /* ifdef LONGPRINT */ + +static void +spans_print_msgbody(objp) + spans_msgbody *objp; +{ + char daddr[80], msgtype_str[80], result_str[80], saddr[80]; + spans_parm_stat_req *streq_p; + spans_parm_stat_ind *stind_p; + spans_parm_stat_rsp *strsp_p; + spans_parm_open_req *opreq_p; + spans_parm_open_ind *opind_p; + spans_parm_open_rsp *oprsp_p; + spans_parm_open_cnf *opcnf_p; + spans_parm_close_req *clreq_p; + spans_parm_close_ind *clind_p; + spans_parm_close_rsp *clrsp_p; + spans_parm_close_cnf *clcnf_p; + spans_parm_rclose_req *rcreq_p; + spans_parm_rclose_ind *rcind_p; + spans_parm_rclose_rsp *rcrsp_p; + spans_parm_rclose_cnf *rccnf_p; + + spans_msgtype_str(&objp->mb_type, msgtype_str); + printf("%s: ", msgtype_str); + switch (objp->mb_type) { + case SPANS_STAT_REQ: + streq_p = &objp->spans_msgbody_u.mb_stat_req; + printf("es_epoch=0x%x", streq_p->streq_es_epoch); + break; + case SPANS_STAT_IND: + stind_p = &objp->spans_msgbody_u.mb_stat_ind; + strncpy(daddr, spans_addr_print(&stind_p->stind_es_addr), + sizeof(daddr)); + strncpy(saddr, spans_addr_print(&stind_p->stind_sw_addr), + sizeof(daddr)); + printf("sw_epoch=0x%x, es_addr=%s, sw_addr=0x%s", + stind_p->stind_sw_epoch, + daddr, saddr); + break; + case SPANS_STAT_RSP: + strsp_p = &objp->spans_msgbody_u.mb_stat_rsp; + strncpy(daddr, spans_addr_print(&strsp_p->strsp_es_addr), + sizeof(daddr)); + printf("es_epoch=0x%x, es_addr=%s", + strsp_p->strsp_es_epoch, daddr); + break; + case SPANS_OPEN_REQ: + opreq_p = &objp->spans_msgbody_u.mb_open_req; + strncpy(daddr, spans_addr_print(&opreq_p->opreq_conn.con_dst), + sizeof(daddr)); + strncpy(saddr, spans_addr_print(&opreq_p->opreq_conn.con_src), + sizeof(saddr)); + printf("daddr=%s, saddr=%s, dsap=%d, ssap=%d, aal=%d", + daddr, saddr, + opreq_p->opreq_conn.con_dsap, + opreq_p->opreq_conn.con_ssap, + opreq_p->opreq_aal); + if (opreq_p->opreq_vpvc.vpf_valid) + printf(", vp.vc=%d.%d", + SPANS_EXTRACT_VPI(opreq_p->opreq_vpvc.vpf_vpvc), + SPANS_EXTRACT_VCI(opreq_p->opreq_vpvc.vpf_vpvc)); + break; + case SPANS_OPEN_IND: + opind_p = &objp->spans_msgbody_u.mb_open_ind; + strncpy(daddr, spans_addr_print(&opind_p->opind_conn.con_dst), + sizeof(daddr)); + strncpy(saddr, spans_addr_print(&opind_p->opind_conn.con_src), + sizeof(saddr)); + printf("daddr=%s, saddr=%s, dsap=%d, ssap=%d, aal=%d", + daddr, saddr, + opind_p->opind_conn.con_dsap, + opind_p->opind_conn.con_ssap, + opind_p->opind_aal); + if (opind_p->opind_vpvc.vpf_valid) + printf(", vp.vc=%d.%d", + SPANS_EXTRACT_VPI(opind_p->opind_vpvc.vpf_vpvc), + SPANS_EXTRACT_VCI(opind_p->opind_vpvc.vpf_vpvc)); + break; + case SPANS_OPEN_RSP: + oprsp_p = &objp->spans_msgbody_u.mb_open_rsp; + strncpy(daddr, spans_addr_print(&oprsp_p->oprsp_conn.con_dst), + sizeof(daddr)); + strncpy(saddr, spans_addr_print(&oprsp_p->oprsp_conn.con_src), + sizeof(saddr)); + spans_result_str(&oprsp_p->oprsp_result, result_str); + printf("result=%s, daddr=%s, saddr=%s, dsap=%d, ssap=%d, vp.vc=%d.%d", + result_str, daddr, saddr, + oprsp_p->oprsp_conn.con_dsap, + oprsp_p->oprsp_conn.con_ssap, + SPANS_EXTRACT_VPI(oprsp_p->oprsp_vpvc), + SPANS_EXTRACT_VCI(oprsp_p->oprsp_vpvc)); + break; + case SPANS_OPEN_CNF: + opcnf_p = &objp->spans_msgbody_u.mb_open_cnf; + strncpy(daddr, spans_addr_print(&opcnf_p->opcnf_conn.con_dst), + sizeof(daddr)); + strncpy(saddr, spans_addr_print(&opcnf_p->opcnf_conn.con_src), + sizeof(saddr)); + spans_result_str(&opcnf_p->opcnf_result, result_str); + printf("result=%s, daddr=%s, saddr=%s, dsap=%d, ssap=%d, vp.vc=%d.%d", + result_str, daddr, saddr, + opcnf_p->opcnf_conn.con_dsap, + opcnf_p->opcnf_conn.con_ssap, + SPANS_EXTRACT_VPI(opcnf_p->opcnf_vpvc), + SPANS_EXTRACT_VCI(opcnf_p->opcnf_vpvc)); + break; + case SPANS_CLOSE_REQ: + clreq_p = &objp->spans_msgbody_u.mb_close_req; + strncpy(daddr, spans_addr_print(&clreq_p->clreq_conn.con_dst), + sizeof(daddr)); + strncpy(saddr, spans_addr_print(&clreq_p->clreq_conn.con_src), + sizeof(saddr)); + printf("daddr=%s, saddr=%s, dsap=%d, ssap=%d", + daddr, saddr, + clreq_p->clreq_conn.con_dsap, + clreq_p->clreq_conn.con_ssap); + break; + case SPANS_CLOSE_IND: + clind_p = &objp->spans_msgbody_u.mb_close_ind; + strncpy(daddr, spans_addr_print(&clind_p->clind_conn.con_dst), + sizeof(daddr)); + strncpy(saddr, spans_addr_print(&clind_p->clind_conn.con_src), + sizeof(saddr)); + printf("daddr=%s, saddr=%s, dsap=%d, ssap=%d", + daddr, saddr, + clind_p->clind_conn.con_dsap, + clind_p->clind_conn.con_ssap); + break; + case SPANS_CLOSE_RSP: + clrsp_p = &objp->spans_msgbody_u.mb_close_rsp; + strncpy(daddr, spans_addr_print(&clrsp_p->clrsp_conn.con_dst), + sizeof(daddr)); + strncpy(saddr, spans_addr_print(&clrsp_p->clrsp_conn.con_src), + sizeof(saddr)); + spans_result_str(&clrsp_p->clrsp_result, result_str); + printf("result=%s, daddr=%s, saddr=%s, dsap=%d, ssap=%d", + result_str, daddr, saddr, + clrsp_p->clrsp_conn.con_dsap, + clrsp_p->clrsp_conn.con_ssap); + break; + case SPANS_CLOSE_CNF: + clcnf_p = &objp->spans_msgbody_u.mb_close_cnf; + strncpy(daddr, spans_addr_print(&clcnf_p->clcnf_conn.con_dst), + sizeof(daddr)); + strncpy(saddr, spans_addr_print(&clcnf_p->clcnf_conn.con_src), + sizeof(saddr)); + spans_result_str(&clcnf_p->clcnf_result, result_str); + printf("result=%s, daddr=%s, saddr=%s, dsap=%d, ssap=%d", + result_str, daddr, saddr, + clcnf_p->clcnf_conn.con_dsap, + clcnf_p->clcnf_conn.con_ssap); + break; + case SPANS_RCLOSE_REQ: + rcreq_p = &objp->spans_msgbody_u.mb_rclose_req; + strncpy(daddr, spans_addr_print(&rcreq_p->rcreq_conn.con_dst), + sizeof(daddr)); + strncpy(saddr, spans_addr_print(&rcreq_p->rcreq_conn.con_src), + sizeof(saddr)); + printf("daddr=%s, saddr=%s, dsap=%d, ssap=%d", + daddr, saddr, + rcreq_p->rcreq_conn.con_dsap, + rcreq_p->rcreq_conn.con_ssap); + break; + case SPANS_RCLOSE_IND: + rcind_p = &objp->spans_msgbody_u.mb_rclose_ind; + strncpy(daddr, spans_addr_print(&rcind_p->rcind_conn.con_dst), + sizeof(daddr)); + strncpy(saddr, spans_addr_print(&rcind_p->rcind_conn.con_src), + sizeof(saddr)); + printf("daddr=%s, saddr=%s, dsap=%d, ssap=%d", + daddr, saddr, + rcind_p->rcind_conn.con_dsap, + rcind_p->rcind_conn.con_ssap); + break; + case SPANS_RCLOSE_RSP: + rcrsp_p = &objp->spans_msgbody_u.mb_rclose_rsp; + strncpy(daddr, spans_addr_print(&rcrsp_p->rcrsp_conn.con_dst), + sizeof(daddr)); + strncpy(saddr, spans_addr_print(&rcrsp_p->rcrsp_conn.con_src), + sizeof(saddr)); + spans_result_str(&rcrsp_p->rcrsp_result, result_str); + printf("result=%s, daddr=%s, saddr=%s, dsap=%d, ssap=%d", + result_str, daddr, saddr, + rcrsp_p->rcrsp_conn.con_dsap, + rcrsp_p->rcrsp_conn.con_ssap); + break; + case SPANS_RCLOSE_CNF: + rccnf_p = &objp->spans_msgbody_u.mb_rclose_cnf; + strncpy(daddr, spans_addr_print(&rccnf_p->rccnf_conn.con_dst), + sizeof(daddr)); + strncpy(saddr, spans_addr_print(&rccnf_p->rccnf_conn.con_src), + sizeof(saddr)); + spans_result_str(&rccnf_p->rccnf_result, result_str); + printf("result=%s, daddr=%s, saddr=%s, dsap=%d, ssap=%d", + result_str, daddr, saddr, + rccnf_p->rccnf_conn.con_dsap, + rccnf_p->rccnf_conn.con_ssap); + break; + } + printf("\n"); +} + +void +spans_print_msg(objp) + spans_msg *objp; +{ + spans_indent = INIT_INDENT; + spans_print_msgbody(&objp->sm_body); +} + +#endif /* ifdef LONGPRINT */ diff --git a/sys/netatm/spans/spans_proto.c b/sys/netatm/spans/spans_proto.c new file mode 100644 index 0000000..e298ed8 --- /dev/null +++ b/sys/netatm/spans/spans_proto.c @@ -0,0 +1,558 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: spans_proto.c,v 1.7 1998/08/26 23:29:10 mks Exp $ + * + */ + +/* + * SPANS Signalling Manager + * --------------------------- + * + * SPANS protocol processing module. + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: spans_proto.c,v 1.7 1998/08/26 23:29:10 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include "spans_xdr.h" +#include <netatm/spans/spans_var.h> + +/* + * Internal functions + */ +caddr_t spans_getname __P((void *)); +void spans_connected __P((void *)); +void spans_cleared __P((void *, struct t_atm_cause *)); +void spans_cpcs_data __P((void *, KBuffer *)); + + +/* + * ATM endpoint for SPANS signalling channel + */ +static Atm_endpoint spans_endpt = { + NULL, /* ep_next */ + ENDPT_SPANS_SIG, /* ep_id */ + NULL, /* ep_ioctl */ + spans_getname, /* ep_getname */ + spans_connected, /* ep_connected */ + spans_cleared, /* ep_cleared */ + NULL, /* ep_incoming */ + NULL, /* ep_addparty */ + NULL, /* ep_dropparty */ + NULL, /* ep_cpcs_ctl */ + spans_cpcs_data, /* ep_cpcs_data */ + NULL, /* ep_saal_ctl */ + NULL, /* ep_saal_data */ + NULL, /* ep_sscop_ctl */ + NULL /* ep_sscop_data */ +}; + + +/* + * ATM connection attributes for UNI signalling channel + */ +static Atm_attributes spans_attr = { + NULL, /* nif */ + CMAPI_CPCS, /* api */ + 0, /* api_init */ + 0, /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, /* aal.tag */ + ATM_AAL3_4 /* aal.aal_type */ + }, + { /* traffic */ + T_ATM_PRESENT, /* traffic.tag */ + { /* traffic.v */ + { /* traffic.v.forward */ + T_ATM_ABSENT, /* PCR_high */ + 0, /* PCR_all */ + T_ATM_ABSENT, /* SCR_high */ + T_ATM_ABSENT, /* SCR_all */ + T_ATM_ABSENT, /* MBS_high */ + T_ATM_ABSENT, /* MBS_all */ + T_NO, /* tagging */ + }, + { /* traffic.v.backward */ + T_ATM_ABSENT, /* PCR_high */ + 0, /* PCR_all */ + T_ATM_ABSENT, /* SCR_high */ + T_ATM_ABSENT, /* SCR_all */ + T_ATM_ABSENT, /* MBS_high */ + T_ATM_ABSENT, /* MBS_all */ + T_NO, /* tagging */ + }, + T_YES, /* best_effort */ + } + }, + { /* bearer */ + T_ATM_PRESENT, /* bearer.tag */ + { /* bearer.v */ + T_ATM_CLASS_X, /* class */ + T_ATM_NULL, /* traffic_type */ + T_ATM_NO_END_TO_END, /* timing_req */ + T_NO, /* clipping */ + T_ATM_1_TO_1, /* conn_conf */ + } + }, + { /* bhli */ + T_ATM_ABSENT, /* bhli.tag */ + }, + { /* blli */ + T_ATM_ABSENT, /* blli.tag_l2 */ + T_ATM_ABSENT, /* blli.tag_l3 */ + }, + { /* llc */ + T_ATM_ABSENT, /* llc.tag */ + }, + { /* called */ + T_ATM_PRESENT, /* called.tag */ + }, + { /* calling */ + T_ATM_ABSENT, /* calling.tag */ + }, + { /* qos */ + T_ATM_PRESENT, /* qos.tag */ + { /* qos.v */ + T_ATM_NETWORK_CODING, /* coding_standard */ + { /* qos.v.forward */ + T_ATM_QOS_CLASS_0, /* class */ + }, + { /* qos.v.backward */ + T_ATM_QOS_CLASS_0, /* class */ + } + } + }, + { /* transit */ + T_ATM_ABSENT, /* transit.tag */ + }, + { /* cause */ + T_ATM_ABSENT, /* cause.tag */ + } +}; + + +/* + * SPANS cause structre + */ +struct t_atm_cause spans_cause = { + T_ATM_ITU_CODING, /* coding_standard */ + T_ATM_LOC_USER, /* location */ + T_ATM_CAUSE_UNSPECIFIED_NORMAL, /* cause_value */ + { 0, 0, 0, 0 } /* diagnostics */ +}; + + +/* + * Process a SPANS timeout + * + * Called when a previously scheduled spans control block timer expires. + * Processing will based on the current SPANS state. + * + * Called at splnet. + * + * Arguments: + * tip pointer to spans timer control block + * + * Returns: + * none + * + */ +void +spans_timer(tip) + struct atm_time *tip; +{ + struct spans *spp; + spans_msg *msg; + Atm_addr_pvc *pvcp; + int err; + + /* + * Back-off to SPANS control block + */ + spp = (struct spans *) + ((caddr_t)tip - (int)(&((struct spans *)0)->sp_time)); + + ATM_DEBUG2("spans_timer: spp=0x%x,state=%d\n", + (int)spp, spp->sp_state); + + /* + * Process timeout based on protocol state + */ + switch (spp->sp_state) { + + case SPANS_INIT: + + /* + * Open signalling channel + */ + spans_attr.nif = spp->sp_pif->pif_nif; + + spans_attr.aal.v.aal4.forward_max_SDU_size = + ATM_NIF_MTU; + spans_attr.aal.v.aal4.backward_max_SDU_size = + ATM_NIF_MTU; + spans_attr.aal.v.aal4.SSCS_type = + T_ATM_SSCS_SSCOP_UNREL; + spans_attr.aal.v.aal4.mid_low = 0; + spans_attr.aal.v.aal4.mid_high = 0; + + spans_attr.called.tag = T_ATM_PRESENT; + spans_attr.called.addr.address_format = T_ATM_PVC_ADDR; + spans_attr.called.addr.address_length = + sizeof(Atm_addr_pvc); + pvcp = (Atm_addr_pvc *)spans_attr.called.addr.address; + ATM_PVC_SET_VPI(pvcp, SPANS_SIG_VPI); + ATM_PVC_SET_VCI(pvcp, SPANS_SIG_VCI); + spans_attr.called.subaddr.address_format = T_ATM_ABSENT; + spans_attr.called.subaddr.address_length = 0; + + spans_attr.traffic.v.forward.PCR_all_traffic = + spp->sp_pif->pif_pcr; + spans_attr.traffic.v.backward.PCR_all_traffic = + spp->sp_pif->pif_pcr; + + err = atm_cm_connect(&spans_endpt, spp, &spans_attr, + &spp->sp_conn); + if (err) { + log(LOG_CRIT, "spans: signalling channel setup failed\n"); + return; + } + + /* + * Signalling channel open, start probing + */ + spp->sp_state = SPANS_PROBE; + + /* FALLTHRU */ + + case SPANS_PROBE: + case SPANS_ACTIVE: + + /* + * Send out SPANS_STAT_REQ message + */ + msg = (spans_msg *)atm_allocate(&spans_msgpool); + if (msg == NULL) { + /* Retry later if no memory */ + SPANS_TIMER(spp, SPANS_PROBE_ERR_WAIT); + break; + } + msg->sm_vers = SPANS_VERS_1_0; + msg->sm_type = SPANS_STAT_REQ; + msg->sm_stat_req.streq_es_epoch = spp->sp_h_epoch; + if (spans_send_msg(spp, msg)) { + /* Retry later if send fails */ + SPANS_TIMER(spp, SPANS_PROBE_ERR_WAIT); + atm_free(msg); + break; + } + atm_free(msg); + spp->sp_probe_ct++; + + /* + * Check whether we're getting an answer to our probes + */ + if (spp->sp_state == SPANS_ACTIVE && + spp->sp_probe_ct > SPANS_PROBE_THRESH) { + /* + * Interface is down, notify VCC owners + */ + spans_switch_reset(spp, SPANS_UNI_DOWN); + + /* + * Set new state and increment host epoch so + * switch knows we reset everyting. + */ + spp->sp_state = SPANS_PROBE; + spp->sp_h_epoch++; + spp->sp_s_epoch = 0; + } + + /* + * Keep sending status requests + */ + SPANS_TIMER(spp, SPANS_PROBE_INTERVAL); + + break; + + case SPANS_DETACH: + /* + * Try to terminate the SPANS signalling PVC + */ + err = atm_cm_release(spp->sp_conn, &spans_cause); + if (err) { + log(LOG_ERR, "spans: can't close signalling channel\n"); + } + break; + + default: + log(LOG_ERR, "spans: timer state: spp=0x%x, state=%d\n", + (int)spp, spp->sp_state); + } +} + + +/* + * Process a SPANS VCC timeout + * + * Called when a previously scheduled SPANS VCCB timer expires. + * Processing will based on the current VCC state. + * + * Called at splnet. + * + * Arguments: + * tip pointer to vccb timer control block + * + * Returns: + * none + * + */ +void +spans_vctimer(tip) + struct atm_time *tip; +{ + int err; + struct spans *spp; + struct spans_vccb *svp; + + /* + * Get VCCB and SPANS control block addresses + */ + svp = (struct spans_vccb *) ((caddr_t)tip - + (int)(&((struct vccb *)0)->vc_time)); + spp = (struct spans *)svp->sv_pif->pif_siginst; + + ATM_DEBUG3("spans_vctimer: svp=0x%x, sstate=%d, ustate=%d\n", + (int)svp, svp->sv_sstate, svp->sv_ustate); + + /* + * Process timeout based on protocol state + */ + switch (svp->sv_sstate) { + + case SPANS_VC_ABORT: + /* + * Kill the VCCB and notify the owner + */ + err = spans_clear_vcc(spp, svp); + break; + + case SPANS_VC_FREE: + /* + * Free VCCB storage + */ + svp->sv_ustate = VCCU_CLOSED; + svp->sv_sstate = SPANS_VC_FREE; + spans_free((struct vccb *)svp); + break; + + case SPANS_VC_POPEN: + /* + * Issued open request, but didn't get response. + */ + if (svp->sv_retry < SV_MAX_RETRY) { + /* + * Retransmit the open request + */ + err = spans_send_open_req(spp, svp); + svp->sv_retry++; + SPANS_VC_TIMER((struct vccb *) svp, SV_TIMEOUT); + } else { + /* + * Retry limit exceeded--report the open failed + */ + svp->sv_ustate = VCCU_CLOSED; + svp->sv_sstate = SPANS_VC_FREE; + svp->sv_connvc->cvc_attr.cause.tag = + T_ATM_PRESENT; + svp->sv_connvc->cvc_attr.cause.v.coding_standard = + T_ATM_ITU_CODING; + svp->sv_connvc->cvc_attr.cause.v.location = + T_ATM_LOC_USER; + svp->sv_connvc->cvc_attr.cause.v.cause_value = + T_ATM_CAUSE_NO_USER_RESPONDING; + KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics, + sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics)); + atm_cm_cleared(svp->sv_connvc); + } + break; + + case SPANS_VC_CLOSE: + /* + * Issued close request, but didn't get response. + */ + if (svp->sv_retry < SV_MAX_RETRY) { + /* + * Retransmit the close request + */ + err = spans_send_close_req(spp, svp); + svp->sv_retry++; + SPANS_VC_TIMER((struct vccb *) svp, SV_TIMEOUT); + } else { + /* + * Retry limit exceeded--just finish the close + */ + svp->sv_sstate = SPANS_VC_FREE; + svp->sv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT; + svp->sv_connvc->cvc_attr.cause.v.coding_standard = + T_ATM_ITU_CODING; + svp->sv_connvc->cvc_attr.cause.v.location = + T_ATM_LOC_USER; + svp->sv_connvc->cvc_attr.cause.v.cause_value = + T_ATM_CAUSE_NO_USER_RESPONDING; + KM_ZERO(svp->sv_connvc->cvc_attr.cause.v.diagnostics, + sizeof(svp->sv_connvc->cvc_attr.cause.v.diagnostics)); + atm_cm_cleared(svp->sv_connvc); + } + break; + + case SPANS_VC_ACTIVE: + case SPANS_VC_ACT_DOWN: + /* + * Shouldn't happen + */ + log(LOG_ERR, "spans_vctimer: unexpected state %d\n", + svp->sv_sstate); + break; + + default: + log(LOG_ERR, "spans: vctimer state: svp=0x%x, sstate=%d\n", + (int)svp, svp->sv_sstate); + } +} + + +/* + * SPANS name routine + * + * Arguments: + * tok SPANS signalling channel token (ignored) + * + * Returns: + * pointer to a string identifying the SPANS signalling manager + * + */ +caddr_t +spans_getname(tok) + void *tok; +{ + return("SPANS"); +} + + +/* + * Process a VCC connection notification + * + * Should never be called + * + * Arguments: + * tok user's connection token (SPANS protocol block) + * + * Returns: + * none + * + */ +void +spans_connected(tok) + void *tok; +{ + struct spans *spp = (struct spans *)tok; + + ATM_DEBUG2("spans_connected: spp=0x%x,state=%d\n", + (int)spp, spp->sp_state); + + /* + * Connected routine shouldn't ever get called for a PVC + */ + log(LOG_ERR, "spans: connected function called, tok=0x%x\n", + (int)spp); +} + + +/* + * Process a VCC close notification + * + * Called when the SPANS signalling channel is closed + * + * Arguments: + * tok user's connection token (spans protocol block) + * cp pointer to cause structure + * + * Returns: + * none + * + */ +void +spans_cleared(tok, cp) + void *tok; + struct t_atm_cause *cp; +{ + struct spans *spp = (struct spans *)tok; + + /* + * VCC has been closed. + */ + log(LOG_ERR, "spans: signalling channel closed\n"); + SPANS_CANCEL(spp); + spp->sp_conn = 0; +} + + +/* + * SPANS CPCS data handler + * + * This is the module which receives data on the SPANS signalling + * channel. Processing is based on the indication received from the + * AAL and the protocol state. + * + * Arguments: + * tok session token (pointer to spans protocol control block) + * m pointer to buffer with data + * + * Returns: + * none + * + */ +void +spans_cpcs_data(tok, m) + void *tok; + KBuffer *m; +{ + struct spans *spp = tok; + + ATM_DEBUG3("spans_cpcs_data: spp=0x%x,state=%d,m=0x%x,\n", + (int)spp, spp->sp_state, m); + + /* + * Process data + */ + spans_rcv_msg(spp, m); +} diff --git a/sys/netatm/spans/spans_subr.c b/sys/netatm/spans/spans_subr.c new file mode 100644 index 0000000..48b9705 --- /dev/null +++ b/sys/netatm/spans/spans_subr.c @@ -0,0 +1,494 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: spans_subr.c,v 1.9 1998/08/26 23:29:10 mks Exp $ + * + */ + +/* + * SPANS Signalling Manager + * --------------------------- + * + * SPANS-related subroutines. + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: spans_subr.c,v 1.9 1998/08/26 23:29:10 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include "spans_xdr.h" +#include <netatm/spans/spans_var.h> + + +/* + * Open a SPANS VCC + * + * Called when a user wants to open a VC. This function will construct + * a VCCB, create the stack requested by the user, and, if we are + * opening an SVC, start the SPANS signalling message exchange. The + * user will have to wait for a notify event to be sure the SVC is fully + * open. + * + * Must be called at splnet. + * + * Arguments: + * spp pointer to SPANS protocol instance + * acp pointer to PVC's connection parameters + * + * Returns: + * 0 VCC creation successful + * errno VCC setup failed - reason indicated + * + */ +int +spans_open_vcc(spp, cvp) + struct spans *spp; + Atm_connvc *cvp; + +{ + struct atm_pif *pip = spp->sp_pif; + struct spans_vccb *svp; + Atm_addr_pvc *pvp; + spans_aal aal; + int err, pvc, vpi, vci; + + ATM_DEBUG2("spans_open_vcc: spp=0x%x, cvp=0x%x\n", spp, cvp); + + /* + * Validate user parameters. AAL and encapsulation are + * checked by the connection manager. + */ + + /* + * Check called party address(es) + */ + if (cvp->cvc_attr.called.tag != T_ATM_PRESENT || + cvp->cvc_attr.called.addr.address_format == + T_ATM_ABSENT || + cvp->cvc_attr.called.subaddr.address_format != + T_ATM_ABSENT) { + return(EINVAL); + } + switch (cvp->cvc_attr.called.addr.address_format) { + case T_ATM_PVC_ADDR: + /* + * Make sure VPI/VCI is valid + */ + pvc = 1; + pvp = (Atm_addr_pvc *)cvp->cvc_attr.called.addr.address; + vpi = ATM_PVC_GET_VPI(pvp); + vci = ATM_PVC_GET_VCI(pvp); + if ((vpi > pip->pif_maxvpi) || + (vci == 0) || + (vci > pip->pif_maxvci)) { + return(ERANGE); + } + + /* + * Make sure VPI/VCI is not already in use + */ + if (spans_find_vpvc(spp, vpi, vci, 0)) { + return(EADDRINUSE); + } + ATM_DEBUG2("spans_open_vcc: VPI.VCI=%d.%d\n", + vpi, vci); + break; + + case T_ATM_SPANS_ADDR: + pvc = 0; + vpi = vci = 0; + + /* + * Check signalling state + */ + if (spp->sp_state != SPANS_ACTIVE) { + return(ENETDOWN); + } + + /* + *Check destination address length + */ + if (cvp->cvc_attr.called.addr.address_length != + sizeof(spans_addr)) { + return(EINVAL); + } + break; + + default: + return(EINVAL); + } + + /* + * Check that this is for the same interface SPANS uses + */ + if (!cvp->cvc_attr.nif || + cvp->cvc_attr.nif->nif_pif != spp->sp_pif) { + return(EINVAL); + } + + /* + * Check AAL + */ + if (!spans_get_spans_aal(cvp->cvc_attr.aal.type, &aal)) { + return(EINVAL); + } + +#ifdef NOTDEF + /* + * Check encapsulation + */ + /* XXX -- How do we check encapsulation? */ + if (cvp->ac_encaps != ATM_ENC_NULL) { + return(EINVAL); + } +#endif + + /* + * Allocate control block for VCC + */ + svp = (struct spans_vccb *)atm_allocate(&spans_vcpool); + if (svp == NULL) { + return(ENOMEM); + } + + /* + * Fill in VCCB + */ + if (pvc) { + svp->sv_type = VCC_PVC | VCC_IN | VCC_OUT; + svp->sv_vpi = vpi; + svp->sv_vci = vci; + svp->sv_sstate = (spp->sp_state == SPANS_ACTIVE ? + SPANS_VC_ACTIVE : SPANS_VC_ACT_DOWN); + svp->sv_ustate = VCCU_OPEN; + } else { + svp->sv_type = VCC_SVC | VCC_OUT; + spans_addr_copy(cvp->cvc_attr.called.addr.address, + &svp->sv_conn.con_dst); + spans_addr_copy(spp->sp_addr.address, + &svp->sv_conn.con_src); + svp->sv_conn.con_dsap = SPANS_SAP_IP; + svp->sv_conn.con_ssap = spans_ephemeral_sap(spp); + svp->sv_sstate = SPANS_VC_POPEN; + svp->sv_ustate = VCCU_POPEN; + } + svp->sv_proto = ATM_SIG_SPANS; + svp->sv_pif = spp->sp_pif; + svp->sv_nif = cvp->cvc_attr.nif; + svp->sv_connvc = cvp; + svp->sv_spans_aal = aal; + svp->sv_tstamp = time_second; + + /* + * Put VCCB on SPANS queue + */ + ENQUEUE(svp, struct spans_vccb, sv_sigelem, spp->sp_vccq); + + /* + * Link VCCB to VCC connection block + */ + cvp->cvc_vcc = (struct vccb *) svp; + + /* + * Start the SPANS message exchange if this is an SVC + */ + if (!pvc) { + svp->sv_retry = 0; + svp->sv_spans_qos.rsc_peak = 1; + svp->sv_spans_qos.rsc_mean = 1; + svp->sv_spans_qos.rsc_burst = 1; + err = spans_send_open_req(spp, svp); + if (err) { + /* + * On error, delete the VCCB + */ + DEQUEUE(svp, struct spans_vccb, sv_sigelem, + spp->sp_vccq); + cvp->cvc_vcc = (struct vccb *)0; + atm_free((caddr_t)svp); + return(err); + } else { + /* + * VCCB is opening--set the retransmit timer + */ + SPANS_VC_TIMER((struct vccb *) svp, SV_TIMEOUT); + } + } + + return(0); +} + + +/* + * Close a SPANS VCC + * + * Called when a user wants to close a VCC. This function will clean + * up the VCCB and, for an SVC, send a close request. + * + * Must be called at splnet. + * + * Arguments: + * spp pointer to SPANS protocol instance + * svp pointer to VCCB for the VCC to be closed + * + * Returns: + * 0 VCC is now closed + * errno error encountered + */ +int +spans_close_vcc(spp, svp, force) + struct spans *spp; + struct spans_vccb *svp; + int force; + +{ + int err = 0; + + ATM_DEBUG2("spans_close_vcc: svp=0x%x, state=%d\n", svp, + svp->sv_sstate); + + /* + * Check that this is for the same interface SPANS uses + */ + if (svp->sv_pif != spp->sp_pif) { + return (EINVAL); + } + + /* + * Kill any possible timer + */ + SPANS_VC_CANCEL((struct vccb *) svp); + + /* + * Mark the close time. + */ + svp->sv_tstamp = time_second; + + /* + * Process based on the connection type + */ + if (svp->sv_type & VCC_PVC) { + svp->sv_sstate = SPANS_VC_FREE; + svp->sv_ustate = VCCU_CLOSED; + } else if (svp->sv_type & VCC_SVC) { + /* + * Update VCCB states + */ + svp->sv_ustate = VCCU_CLOSED; + + /* + * Send the appropriate SPANS close message + */ + switch (svp->sv_sstate) { + case SPANS_VC_R_POPEN: + err = spans_send_open_rsp(spp, svp, SPANS_FAIL); + svp->sv_sstate = SPANS_VC_FREE; + break; + case SPANS_VC_OPEN: + case SPANS_VC_POPEN: + case SPANS_VC_ABORT: + svp->sv_retry = 0; + err = spans_send_close_req(spp, svp); + if (force) { + svp->sv_sstate = SPANS_VC_FREE; + } else { + svp->sv_sstate = SPANS_VC_CLOSE; + SPANS_VC_TIMER((struct vccb *) svp, + SV_TIMEOUT); + } + break; + case SPANS_VC_CLOSE: + if (force) { + svp->sv_sstate = SPANS_VC_FREE; + } + break; + } + } + + /* + * Wait for user to free resources + */ + return(err); +} + + +/* + * Clear a SPANS VCC + * + * Called when the signalling manager wants to close a VCC immediately. + * This function will clean up the VCCB and notify the owner. + * + * Must be called at splnet. + * + * Arguments: + * spp pointer to SPANS protocol instance + * svp pointer to VCCB for the VCC to be closed + * + * Returns: + * 0 VCC is now closed + * errno error encountered + */ +int +spans_clear_vcc(spp, svp) + struct spans *spp; + struct spans_vccb *svp; + +{ + u_char outstate; + + ATM_DEBUG2("spans_clear_vcc: svp=0x%x, state=%d\n", svp, + svp->sv_sstate); + + /* + * Check that this is for the same interface SPANS uses + */ + if (svp->sv_pif != spp->sp_pif) { + return (EINVAL); + } + + /* + * Kill any possible timer + */ + SPANS_VC_CANCEL((struct vccb *) svp); + + /* + * Mark the close time + */ + svp->sv_tstamp = time_second; + + /* + * Mark the VCCB closed + */ + outstate = svp->sv_sstate; + svp->sv_sstate = SPANS_VC_FREE; + svp->sv_ustate = VCCU_CLOSED; + + /* + * Notify the user if old state indicates. + */ + switch (outstate) { + case SPANS_VC_ACTIVE: + case SPANS_VC_ACT_DOWN: + case SPANS_VC_POPEN: + case SPANS_VC_OPEN: + case SPANS_VC_CLOSE: + case SPANS_VC_ABORT: + /* XXX -- set cause */ + atm_cm_cleared(svp->sv_connvc); + break; + case SPANS_VC_NULL: + case SPANS_VC_R_POPEN: + case SPANS_VC_FREE: + break; + } + + /* + * Wait for user to free resources + */ + return(0); +} + + +/* + * Reset the switch state + * + * Called when the switch or host at the far end of the ATM link has + * gone away. This can be deteched either by a number of SPANS_STAT_REQ + * messages going unanswered or by the host epoch changing in a SPANS + * SPANS_STAT_IND or SPANS_STAT_REQ message. + * + * Arguments: + * spp pointer to SPANS protocol instance + * + * Returns: + * none + * + */ +void +spans_switch_reset(spp, cause) + struct spans *spp; + int cause; + +{ + int s; + struct vccb *vcp, *vnext; + + ATM_DEBUG2("spans_switch_reset: spp=0x%x, cause=%d\n", + spp, cause); + + /* + * Log the event + */ + log(LOG_INFO, "spans: signalling %s on interface %s%d\n", + (cause == SPANS_UNI_DOWN ? "down" : "up"), + spp->sp_pif->pif_name, + spp->sp_pif->pif_unit); + + /* + * Terminate all of our VCCs + */ + s = splnet(); + for (vcp = Q_HEAD(spp->sp_vccq, struct vccb); vcp; + vcp = vnext) { + + u_char outstate; + + vnext = Q_NEXT(vcp, struct vccb, vc_sigelem); + + if (vcp->vc_type & VCC_SVC) { + /* + * Close the SVC and notify the owner + */ + outstate = vcp->vc_sstate; + SPANS_VC_CANCEL((struct vccb *) vcp); + vcp->vc_ustate = VCCU_CLOSED; + vcp->vc_sstate = SPANS_VC_FREE; + if (outstate == SPANS_VC_OPEN || + outstate == SPANS_VC_POPEN) { + /* XXX -- set cause */ + atm_cm_cleared(vcp->vc_connvc); + } + } else if (vcp->vc_type & VCC_PVC) { + /* + * Note new state + */ + switch(cause) { + case SPANS_UNI_DOWN: + vcp->vc_sstate = SPANS_VC_ACT_DOWN; + break; + case SPANS_UNI_UP: + vcp->vc_sstate = SPANS_VC_ACTIVE; + break; + } + } else { + log(LOG_ERR, "spans: invalid VCC type: vccb=0x%x, type=%d\n", + vcp, vcp->vc_type); + } + } + (void) splx(s); +} diff --git a/sys/netatm/spans/spans_util.c b/sys/netatm/spans/spans_util.c new file mode 100644 index 0000000..6d470e1 --- /dev/null +++ b/sys/netatm/spans/spans_util.c @@ -0,0 +1,477 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: spans_util.c,v 1.6 1998/08/26 23:29:10 mks Exp $ + * + */ + +/* + * SPANS Signalling Manager + * --------------------------- + * + * SPANS-related utility routines. + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: spans_util.c,v 1.6 1998/08/26 23:29:10 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include "spans_xdr.h" +#include <netatm/spans/spans_var.h> + + +#ifdef NOTDEF +/* XXX -- Remove all SAP checks? */ +#define MAX_SAP_ENT 1 +static struct { + spans_sap spans_sap; + Sap_t local_sap; +} sap_table[MAX_SAP_ENT] = { + {SPANS_SAP_IP, SAP_IP}, +}; + + +/* + * Translate an internal SAP to a SPANS SAP + * + * Search the SAP table for the given SAP. Put the corresponding SPANS + * SAP into the indicated variable. + * + * Arguments: + * lsap the value of the internal SAP + * ssap a pointer to the variable to receive the SPANS SAP value + * + * Returns: + * TRUE the SAP was found; *ssap is valid + * FALSE the SAP was not found; *ssap is not valid + * + */ +int +spans_get_spans_sap(lsap, ssap) + Sap_t lsap; + spans_sap *ssap; +{ + int i; + + /* + * Search the SAP table for the given local SAP + */ + for (i=0; i< MAX_SAP_ENT; i++) { + if (sap_table[i].local_sap == lsap) { + *ssap = sap_table[i].spans_sap; + return(TRUE); + } + } + return(FALSE); +} + + +/* + * Translate a SPANS SAP to internal format + * + * Search the SAP table for the given SAP. Put the corresponding + * internal SAP into the indicated variable. + * + * Arguments: + * ssap the value of the SPANS SAP + * lsap a pointer to the variable to receive the internal + * SAP value + * + * Returns: + * TRUE the SAP was found; *lsap is valid + * FALSE the SAP was not found; *lsap is not valid + * + */ +int +spans_get_local_sap(ssap, lsap) + spans_sap ssap; + Sap_t *lsap; +{ + int i; + + /* + * Search the SAP table for the given SPANS SAP + */ + for (i=0; i< MAX_SAP_ENT; i++) { + if (sap_table[i].spans_sap == ssap) { + *lsap = sap_table[i].local_sap; + return(TRUE); + } + } + return(FALSE); +} +#endif + + +/* + * Allocate an ephemeral SPANS SAP + * + * Arguments: + * spp pointer to SPANS protocol instance + * + * Returns: + * a SPANS ephemeral SAP number + * + */ +int +spans_ephemeral_sap(spp) + struct spans *spp; +{ + return(SPANS_SAP_EPHEMERAL); +} + + +/* + * Translate an internal AAL designator to a SPANS AAL type + * + * Arguments: + * laal internal AAL designation + * saal a pointer to the variable to receive the SPANS AAL type + * + * Returns: + * TRUE the AAL was found; *saal is valid + * FALSE the AAL was not found; *saal is not valid + * + */ +int +spans_get_spans_aal(laal, saal) + Aal_t laal; + spans_aal *saal; +{ + /* + * + */ + switch (laal) { + case ATM_AAL0: + *saal = SPANS_AAL0; + return(TRUE); + case ATM_AAL1: + *saal = SPANS_AAL1; + return(TRUE); + case ATM_AAL2: + *saal = SPANS_AAL2; + return(TRUE); + case ATM_AAL3_4: + *saal = SPANS_AAL4; + return(TRUE); + case ATM_AAL5: + *saal = SPANS_AAL5; + return(TRUE); + default: + return(FALSE); + } +} + + +/* + * Translate a SPANS AAL type to an internal AAL designator + * + * Arguments: + * saal the SPANS AAL type + * laal a pointer to the variable to receive the internal + * AAL designation + * + * Returns: + * TRUE the AAL was found; *laal is valid + * FALSE the AAL was not found; *laal is not valid + * + */ +int +spans_get_local_aal(saal, laal) + spans_aal saal; + Aal_t *laal; +{ + /* + * + */ + switch (saal) { + case SPANS_AAL0: + *laal = ATM_AAL0; + return(TRUE); + case SPANS_AAL1: + *laal = ATM_AAL1; + return(TRUE); + case SPANS_AAL2: + *laal = ATM_AAL2; + return(TRUE); + case SPANS_AAL3: + case SPANS_AAL4: + *laal = ATM_AAL3_4; + return(TRUE); + case SPANS_AAL5: + *laal = ATM_AAL5; + return(TRUE); + default: + return(FALSE); + } +} + + +/* + * Verify a VCCB + * + * Search SPANS's VCCB queue to verify that a VCCB belongs to SPANS. + * + * Arguments: + * spp pointer to SPANS protocol instance + * svp pointer to a VCCB + * + * Returns: + * TRUE the VCCB belongs to SPANS + * FALSE the VCCB doesn't belong to SPANS + * + */ +int +spans_verify_vccb(spp, svp) + struct spans *spp; + struct spans_vccb *svp; + +{ + struct spans_vccb *vcp, *vcnext; + + for (vcp = Q_HEAD(spp->sp_vccq, struct spans_vccb); + vcp; vcp = vcnext){ + vcnext = Q_NEXT(vcp, struct spans_vccb, sv_sigelem); + if (svp == vcp) { + return(TRUE); + } + } + return(FALSE); +} + + +/* + * Find a VCCB + * + * Find a VCCB given the VPI and VCI. + * + * Arguments: + * spp pointer to SPANS protocol instance + * vpi the VPI to search for + * vci the VCI to search for + * dir the direction of the VCC (VCC_IN, VCC_OUT, or both). + * If dir is set to zero, return the address of any VCCB + * with the given VPI/VCI, regardless of direction. + * + * Returns: + * 0 there is no such VCCB + * address the address of the VCCB + * + */ +struct spans_vccb * +spans_find_vpvc(spp, vpi, vci, dir) + struct spans *spp; + int vpi, vci; + u_char dir; + +{ + struct spans_vccb *svp, *svnext; + + for (svp = Q_HEAD(spp->sp_vccq, struct spans_vccb); svp; + svp = svnext){ + svnext = Q_NEXT(svp, struct spans_vccb, sv_sigelem); + if (svp->sv_vpi == vpi && + svp->sv_vci == vci && + (svp->sv_type & dir) == dir) + break; + } + return(svp); +} + + +/* + * Find a connection + * + * Find a VCCB given the connection structure. + * + * Arguments: + * spp pointer to SPANS protocol instance + * p pointer to an spans_atm_conn structure + * + * Returns: + * 0 there is no such VCCB + * address the address of the VCCB + * + */ +struct spans_vccb * +spans_find_conn(spp, p) + struct spans *spp; + struct spans_atm_conn *p; +{ + struct spans_vccb *svp, *svnext; + + for (svp = Q_HEAD(spp->sp_vccq, struct spans_vccb); svp; svp = svnext){ + svnext = Q_NEXT(svp, struct spans_vccb, sv_sigelem); + if (!bcmp(p, &svp->sv_conn, sizeof (spans_atm_conn))) + break; + } + return(svp); +} + + +/* + * Allocate a VPI/VCI pair + * + * When we get an open request or indication from the network, we have + * allocate a VPI and VCI for the conection. This routine will allocate + * a VPI/VCI based on the next available VCI in the SPANS protocol block. + * The VPI/VCI chose must be within the range allowed by the interface and + * must not already be in use. + * + * Currently the Fore ATM interface only supports VPI 0, so this code only + * allocates a VCI. + * + * There's probably a more elegant way to do this. + * + * Arguments: + * spp pointer to connection's SPANS protocol instance + * + * Returns: + * 0 no VPI/VCI available + * vpvc the VPI/VCI for the connection + * + */ +spans_vpvc +spans_alloc_vpvc(spp) + struct spans *spp; +{ + int vpi, vci; + + /* + * Loop through the allowable VCIs, starting with the curent one, + * to find one that's not in use. + */ + while (spp->sp_alloc_vci <= spp->sp_max_vci) { + vpi = spp->sp_alloc_vpi; + vci = spp->sp_alloc_vci++; + if (!spans_find_vpvc(spp, vpi, vci, 0)) { + return(SPANS_PACK_VPIVCI(vpi, vci)); + } + } + + /* + * Reset the VCI to the minimum + */ + spp->sp_alloc_vci = spp->sp_min_vci; + + /* + * Try looping through again + */ + while (spp->sp_alloc_vci <= spp->sp_max_vci) { + vpi = spp->sp_alloc_vpi; + vci = spp->sp_alloc_vci++; + if (!spans_find_vpvc(spp, vpi, vci, 0)) { + return(SPANS_PACK_VPIVCI(vpi, vci)); + } + } + + /* + * All allowable VCIs are in use + */ + return(0); +} + + +/* + * Print a SPANS address + * + * Convert a SPANS address into an ASCII string suitable for printing. + * + * Arguments: + * p pointer to a struct spans_addr + * + * Returns: + * the address of a string with the ASCII representation of the + * address. + * + */ +char * +spans_addr_print(p) + struct spans_addr *p; +{ + static char strbuff[80]; + union { + int w; + char c[4]; + } u1, u2; + + + /* + * Clear the returned string + */ + KM_ZERO(strbuff, sizeof(strbuff)); + + /* + * Get address into integers + */ + u1.c[0] =p->addr[0]; + u1.c[1] =p->addr[1]; + u1.c[2] =p->addr[2]; + u1.c[3] =p->addr[3]; + u2.c[0] =p->addr[4]; + u2.c[1] =p->addr[5]; + u2.c[2] =p->addr[6]; + u2.c[3] =p->addr[7]; + + /* + * Print and return the string + */ + sprintf(strbuff, "%x.%x", ntohl(u1.w), ntohl(u2.w)); + return(strbuff); +} + + +/* + * Print a buffer chain + * + * Arguments: + * m pointer to a buffer chain + * + * Returns: + * none + * + */ +void +spans_dump_buffer(m) + KBuffer *m; +{ + int i; + caddr_t cp; + + printf("spans_dump_buffer:\n"); + while (m) { + KB_DATASTART(m, cp, caddr_t); + for (i = 0; i < KB_LEN(m); i++) { + if (i == 0) + printf(" bfr=0x%x: ", (int)m); + printf("%x ", (u_char)*cp++); + } + printf("<end_bfr>\n"); + m = KB_NEXT(m); + } +} diff --git a/sys/netatm/spans/spans_var.h b/sys/netatm/spans/spans_var.h new file mode 100644 index 0000000..8f9ac8a --- /dev/null +++ b/sys/netatm/spans/spans_var.h @@ -0,0 +1,259 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: spans_var.h,v 1.7 1998/04/09 14:24:18 johnc Exp $ + * + */ + +/* + * SPANS Signalling Manager + * --------------------------- + * + * Protocol control blocks + * + */ + +#ifndef _SPANS_SPANS_VAR_H +#define _SPANS_SPANS_VAR_H + +#ifdef ATM_KERNEL +/* + * Constants to indicate the state of the signalling interface + */ +#define SPANS_UNI_UP 1 +#define SPANS_UNI_DOWN -1 + + +/* + * Structure containing state information for each SPANS protocol + * instance. There will be one instance for each ATM device interface + * using the SPANS signalling manager. + */ +struct spans { + struct siginst sp_inst; /* Header */ + struct atm_time sp_time; /* Timer controls */ + void (*sp_lower) /* Lower command handler */ + __P((int, void *, int, int)); + Atm_connection *sp_conn; /* Signalling connection */ + long sp_s_epoch; /* Switch epoch */ + long sp_h_epoch; /* Host epoch */ + u_int sp_probe_ct; /* Status_req msgs unanswered */ + u_int sp_alloc_vci; /* Next VCI to allocate */ + u_int sp_alloc_vpi; /* Next VPI to allocate */ + u_int sp_min_vci; /* Lowest VCI to allocate */ + u_int sp_max_vci; /* Highest VCI to allocate */ + struct spanscls *sp_cls; /* CLS instance */ +}; + +#define sp_next sp_inst.si_next +#define sp_pif sp_inst.si_pif +#define sp_addr sp_inst.si_addr +#define sp_subaddr sp_inst.si_subaddr +#define sp_vccq sp_inst.si_vccq +#define sp_state sp_inst.si_state +#define sp_ipserv sp_inst.si_ipserv +#endif /* ATM_KERNEL */ + +/* + * SPANS Protocol States + */ +#define SPANS_ACTIVE 1 /* Active */ +#define SPANS_DETACH 2 /* Detach in progress */ +#define SPANS_INIT 3 /* Initializing */ +#define SPANS_PROBE 4 /* Exchanging status info */ + +#define SPANS_PROBE_INTERVAL (ATM_HZ) /* Interval between SPANS_STAT_REQs */ +#define SPANS_PROBE_THRESH 10 /* Probe time-out threshold */ +#define SPANS_PROBE_ERR_WAIT (3 * ATM_HZ) /* Time to wait if send probe fails */ + + +#ifdef ATM_KERNEL +/* + * SPANS Virtual Channel Connection control block. All information + * regarding the state of a SPANS-controlled VCC will be recorded here. + * There will be one SPANS VCC control block for each SPANS-controlled + * VCC. + */ +struct spans_vccb { + struct vccb vcp_hdr; /* Generic VCCB */ + u_short sv_retry; /* Xmit retry count */ + spans_atm_conn sv_conn; /* SPANS connection info */ + spans_resrc sv_spans_qos; /* QoS for VCC */ + spans_aal sv_spans_aal; /* AAL for VCC */ +}; + +#define sv_type vcp_hdr.vc_type +#define sv_proto vcp_hdr.vc_proto +#define sv_sstate vcp_hdr.vc_sstate +#define sv_ustate vcp_hdr.vc_ustate +#define sv_pif vcp_hdr.vc_pif +#define sv_nif vcp_hdr.vc_nif +#define sv_sigelem vcp_hdr.vc_sigelem +#define sv_time vcp_hdr.vc_time +#define sv_vpi vcp_hdr.vc_vpi +#define sv_vci vcp_hdr.vc_vci +#define sv_connvc vcp_hdr.vc_connvc +#define sv_ipdus vcp_hdr.vc_ipdus +#define sv_opdus vcp_hdr.vc_opdus +#define sv_ibytes vcp_hdr.vc_ibytes +#define sv_obytes vcp_hdr.vc_obytes +#define sv_ierrors vcp_hdr.vc_ierrors +#define sv_oerrors vcp_hdr.vc_oerrors +#define sv_tstamp vcp_hdr.vc_tstamp +#define sv_daddr sv_conn.daddr +#define sv_saddr sv_conn.saddr +#define sv_dsap sv_conn.dsap +#define sv_ssap sv_conn.ssap + +#define SV_MAX_RETRY 3 +#define SV_TIMEOUT (ATM_HZ) + +#endif /* ATM_KERNEL */ + + +/* + * SPANS VCC Signalling Protocol States + */ +#define SPANS_VC_NULL 0 /* No state */ +#define SPANS_VC_ACTIVE 1 /* Active */ +#define SPANS_VC_ACT_DOWN 2 /* Active - Interface down */ +#define SPANS_VC_POPEN 3 /* VCC open in progress */ +#define SPANS_VC_R_POPEN 4 /* VCC rmt open in progress */ +#define SPANS_VC_OPEN 5 /* VCC open */ +#define SPANS_VC_CLOSE 6 /* VCC close in progress */ +#define SPANS_VC_ABORT 7 /* VCC abort in progress */ +#define SPANS_VC_FREE 8 /* Waiting for user to free resources */ + + +#ifdef ATM_KERNEL +/* + * Macro to compare two SPANS addresses. + * + * Returns 0 if the addresses are equal. + */ +#define spans_addr_cmp(a, b) \ + (bcmp((caddr_t)a, (caddr_t)b, sizeof(struct spans_addr))) + +/* + * Macro to copy a SPANS address from a to b. + */ +#define spans_addr_copy(a, b) \ + (KM_COPY((caddr_t)a, (caddr_t)b, sizeof(struct spans_addr))) + + +/* + * Timer macros + */ +#define SPANS_TIMER(s, t) atm_timeout(&(s)->sp_time, (t), spans_timer) +#define SPANS_CANCEL(s) atm_untimeout(&(s)->sp_time) +#define SPANS_VC_TIMER(v, t) atm_timeout(&(v)->vc_time, (t), spans_vctimer) +#define SPANS_VC_CANCEL(v) atm_untimeout(&(v)->vc_time) + + +/* + * Global function declarations + */ +struct ipvcc; + + /* spans_arp.c */ +int spansarp_svcout __P((struct ipvcc *, struct in_addr *)); +int spansarp_svcin __P((struct ipvcc *, Atm_addr *, Atm_addr *)); +int spansarp_svcactive __P((struct ipvcc *)); +void spansarp_vcclose __P((struct ipvcc *)); +void spansarp_ipact __P((struct spanscls *)); +void spansarp_ipdact __P((struct spanscls *)); +void spansarp_stop __P((void)); +void spansarp_input __P((struct spanscls *, KBuffer *)); +int spansarp_ioctl __P((int, caddr_t, caddr_t)); + + /* spans_cls.c */ +int spanscls_start __P((void)); +void spanscls_stop __P((void)); +int spanscls_attach __P((struct spans *)); +void spanscls_detach __P((struct spans *)); +void spanscls_closevc __P((struct spanscls *, + struct t_atm_cause *)); + + /* spans_if.c */ +int spans_abort __P((struct vccb *)); +int spans_free __P((struct vccb *)); + + /* spans_msg.c */ +int spans_send_msg __P((struct spans *, spans_msg *)); +int spans_send_open_req __P((struct spans *, + struct spans_vccb *)); +int spans_send_open_rsp __P((struct spans *, + struct spans_vccb *, + spans_result)); +int spans_send_close_req __P((struct spans *, + struct spans_vccb *)); +void spans_rcv_msg __P((struct spans *, KBuffer *)); + + /* spans_print.c */ +void spans_print_msg __P((spans_msg *)); + + /* spans_proto.c */ +void spans_timer __P((struct atm_time *)); +void spans_vctimer __P((struct atm_time *)); +void spans_upper __P((int, void *, int, int)); +void spans_notify __P((void *, int, int)); + + /* spans_subr.c */ +int spans_open_vcc __P((struct spans *, Atm_connvc *)); +int spans_close_vcc __P((struct spans *, + struct spans_vccb *, int)); +int spans_clear_vcc __P((struct spans *, + struct spans_vccb *)); +void spans_switch_reset __P((struct spans *, int)); + + /* spans_util.c */ +int spans_get_spans_sap __P((Sap_t, spans_sap *)); +int spans_get_local_sap __P((spans_sap, Sap_t *)); +int spans_ephemeral_sap __P((struct spans *)); +int spans_get_spans_aal __P((Aal_t, spans_aal *)); +int spans_get_local_aal __P((spans_aal, Aal_t *)); +int spans_verify_vccb __P((struct spans *, + struct spans_vccb *)); +struct spans_vccb * + spans_find_vpvc __P((struct spans *, int, int, u_char)); +struct spans_vccb * + spans_find_conn __P((struct spans *, + struct spans_atm_conn *)); +spans_vpvc spans_alloc_vpvc __P((struct spans *)); +char * spans_addr_print __P((struct spans_addr *)); +void spans_dump_buffer __P((KBuffer *)); + + +/* + * External variables + */ +extern struct spans_addr spans_bcastaddr; +extern struct sp_info spans_vcpool; +extern struct sp_info spans_msgpool; +extern struct t_atm_cause spans_cause; + +#endif /* ATM_KERNEL */ + +#endif /* _SPANS_SPANS_VAR_H */ diff --git a/sys/netatm/spans/spans_xdr.x b/sys/netatm/spans/spans_xdr.x new file mode 100644 index 0000000..7e53f53 --- /dev/null +++ b/sys/netatm/spans/spans_xdr.x @@ -0,0 +1,513 @@ +%/* +% * +% * =================================== +% * 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. +% * +% * @(#) $Id: spans_xdr.x,v 1.4 1997/05/06 22:17:36 mks Exp $ +% * +% */ +% +/* + * SPANS Signalling Manager + * --------------------------- + * + * SPANS Protocol Message XDR Specification + * + */ + +#ifdef RPC_HDR +%/* +% * SPANS Signalling Manager +% * --------------------------- +% * +% * SPANS Protocol Message Definitions +% * +% */ +% +%#ifndef _SPANS_SPANS_XDR_H +%#define _SPANS_SPANS_XDR_H +% +%#include <rpc/types.h> +% +#endif + +#ifdef RPC_XDR +%/* +% * SPANS Signalling Manager +% * --------------------------- +% * +% * SPANS Protocol Message XDR Routines +% * +% */ +% +%#ifndef lint +%static char *RCSid = "@(#) $Id: spans_xdr.x,v 1.4 1997/05/06 22:17:36 mks Exp $"; +%#endif +% +#endif + + +/* + * SPANS Signalling + */ +const SPANS_SIG_VPI = 0; /* Signalling VPI */ +const SPANS_SIG_VCI = 15; /* Signalling VCI */ +const SPANS_CLS_VPI = 0; /* Connectionless VPI */ +const SPANS_CLS_VCI = 14; /* Connectionless VCI */ + +const SPANS_MIN_VCI = 32; /* Lowest VCI to allocate */ +const SPANS_MAX_VCI = 1023; /* Highest VCI to allocate */ +const SPANS_VPI = 0; /* Only VPI to allocate */ + +/* + * SPANS Protocol Version + * + * Major_version * 256 + Minor_version + */ +typedef u_int spans_version; + +const SPANS_VERS_1_0 = 0x0100; /* Version 1.0 */ + + +/* + * VPI/VCI + * + * Format: + * 4 bits - unused + * 12 bits - VPI value + * 16 bits - VCI value + */ +typedef u_int spans_vpvc; /* VPI/VCI value */ + +#ifdef RPC_HDR +%#define SPANS_EXTRACT_VPI(p) (((p) >> 16) & 0x0FFF) +%#define SPANS_EXTRACT_VCI(p) ((p) & 0x0FFFF) +%#define SPANS_PACK_VPIVCI(p, c) ((((p) & 0x0FFF) << 16) | ((c) & 0x0FFFF)) +#endif + + +/* + * VPI/VCI Preference + */ +struct spans_vpvc_pref { + bool vpf_valid; /* VPI/VCI values valid */ + spans_vpvc vpf_vpvc; /* VPI/VCI value */ +}; + + +/* + * SPANS ATM Address + */ +struct spans_addr { + opaque addr[8]; /* SPANS ATM address */ +}; + + +/* + * Service Access Point (SAP) + */ +typedef u_int spans_sap; /* SAP value */ + +const SPANS_SAP_IP = 1025; /* TCP/IP */ +const SPANS_SAP_EPHEMERAL = 2048; /* Start of ephemeral SAPs*/ + + +/* + * ATM Connection Identifier + */ +struct spans_atm_conn { + spans_addr con_dst; /* Destination ATM address */ + spans_addr con_src; /* Source ATM address */ + spans_sap con_dsap; /* Destination SAP */ + spans_sap con_ssap; /* Source SAP */ +}; + + +/* + * Connection Resources + */ +struct spans_resrc { + u_int rsc_peak; /* Peak bandwidth (Kbps) */ + u_int rsc_mean; /* Mean bandwidth (Kbps) */ + u_int rsc_burst; /* Mean burst (Kb) */ +}; + + +/* + * ATM Adaptation Layer (AAL) Types + */ +enum spans_aal { + SPANS_AAL0 = 0, /* NULL AAL */ + SPANS_AAL1 = 1, /* AAL 1 */ + SPANS_AAL2 = 2, /* AAL 2 */ + SPANS_AAL3 = 3, /* AAL 3 */ + SPANS_AAL4 = 4, /* AAL 4 */ + SPANS_AAL5 = 5 /* AAL 5 */ +}; + + +/* + * Result Codes + */ +enum spans_result { + SPANS_OK = 0, /* Success */ + SPANS_FAIL = 1, /* Failure */ + SPANS_NOVPVC = 2, /* No VP/VC */ + SPANS_NORSC = 3, /* No resources */ + SPANS_BADDEST = 4 /* Bad destination */ +}; + + +/* + * Message Types + */ +enum spans_msgtype { + /* + * SPANS UNI message types + */ + SPANS_STAT_REQ = 0, /* Status request */ + SPANS_STAT_IND = 1, /* Status indication */ + SPANS_STAT_RSP = 2, /* Status response */ + SPANS_OPEN_REQ = 3, /* Open request */ + SPANS_OPEN_IND = 4, /* Open indication */ + SPANS_OPEN_RSP = 5, /* Open response */ + SPANS_OPEN_CNF = 6, /* Open confirmation */ + SPANS_CLOSE_REQ = 7, /* Close request */ + SPANS_CLOSE_IND = 8, /* Close indication */ + SPANS_CLOSE_RSP = 9, /* Close response */ + SPANS_CLOSE_CNF = 10, /* Close confirmation */ + SPANS_RCLOSE_REQ = 11, /* Reverse close request */ + SPANS_RCLOSE_IND = 12, /* Reverse close indication */ + SPANS_RCLOSE_RSP = 13, /* Reverse close response */ + SPANS_RCLOSE_CNF = 14, /* Reverse close confirmation */ + SPANS_MULTI_REQ = 15, /* Multicast request */ + SPANS_MULTI_IND = 16, /* Multicast indication */ + SPANS_MULTI_RSP = 17, /* Multicast response */ + SPANS_MULTI_CNF = 18, /* Multicast confirmation */ + SPANS_ADD_REQ = 19, /* Add request */ + SPANS_ADD_IND = 20, /* Add indication */ + SPANS_ADD_RSP = 21, /* Add response */ + SPANS_ADD_CNF = 22, /* Add confirmation */ + SPANS_JOIN_REQ = 23, /* Join request */ + SPANS_JOIN_CNF = 24, /* Join confirmation */ + SPANS_LEAVE_REQ = 25, /* Leave request */ + SPANS_LEAVE_CNF = 26, /* Leave confirmation */ + + /* + * SPANS NNI message types + */ + SPANS_NSAP_IND = 99, /* NSAP routing message */ + SPANS_MAP_IND = 100, /* Topology message */ + SPANS_SETUP_REQ = 101, /* Setup request */ + SPANS_SETUP_RSP = 102, /* Setup response */ + SPANS_CHANGE_REQ = 103, /* Change request */ + SPANS_CHANGE_RSP = 104, /* Change response */ + SPANS_RELOC_REQ = 105, /* Relocation request */ + SPANS_RELOC_RSP = 106, /* Relocation response */ + SPANS_HELLO_IND = 107, /* Hello message */ + + SPANS_VCIR_IND = 108, /* VCI range indication */ + SPANS_QUERY_REQ = 110, /* Conn. state query request */ + SPANS_QUERY_RSP = 111 /* Conn. state query response */ +}; + + +/* + * Query types + */ +enum spans_query_type { + SPANS_QUERY_NORMAL, /* Normal--respond */ + SPANS_QUERY_DEBUG, /* Debug--respond with state */ + SPANS_QUERY_END_TO_END /* Not implemented */ +}; + + +/* + * SPANS connection states + */ +enum spans_conn_state { + SPANS_CONN_OPEN, /* Connection is open */ + SPANS_CONN_OPEN_PEND, /* Connection is being opened */ + SPANS_CONN_CLOSE_PEND, /* Connection is being closed */ + SPANS_CONN_CLOSED /* Connection does not exist */ +}; + + +/* + * Message Parameters + * + * There is a separate message parameter structure for each + * message type. + */ +struct spans_parm_stat_req { + u_long streq_es_epoch; /* End system epoch */ +}; + +struct spans_parm_stat_ind { + u_long stind_sw_epoch; /* Switch epoch */ + spans_addr stind_es_addr; /* End system ATM address */ + spans_addr stind_sw_addr; /* Switch ATM address */ +}; + +struct spans_parm_stat_rsp { + u_long strsp_es_epoch; /* End system epoch */ + spans_addr strsp_es_addr; /* End system ATM address */ +}; + +struct spans_parm_open_req { + spans_atm_conn opreq_conn; /* Connection identity */ + spans_aal opreq_aal; /* AAL type */ + spans_resrc opreq_desrsrc; /* Desired resources */ + spans_resrc opreq_minrsrc; /* Minimum resources */ + spans_vpvc_pref opreq_vpvc; /* VPI/VCI preference */ +}; + +struct spans_parm_open_ind { + spans_atm_conn opind_conn; /* Connection identity */ + spans_aal opind_aal; /* AAL type */ + spans_resrc opind_desrsrc; /* Desired resources */ + spans_resrc opind_minrsrc; /* Minimum resources */ + spans_vpvc_pref opind_vpvc; /* VPI/VCI preference */ +}; + +struct spans_parm_open_rsp { + spans_atm_conn oprsp_conn; /* Connection identity */ + spans_result oprsp_result; /* Open result */ + spans_resrc oprsp_rsrc; /* Allocated resources */ + spans_vpvc oprsp_vpvc; /* Allocated VPI/VCI */ +}; + +struct spans_parm_open_cnf { + spans_atm_conn opcnf_conn; /* Connection identity */ + spans_result opcnf_result; /* Open result */ + spans_resrc opcnf_rsrc; /* Allocated resources */ + spans_vpvc opcnf_vpvc; /* Allocated VPI/VCI */ +}; + +struct spans_parm_close_req { + spans_atm_conn clreq_conn; /* Connection identity */ +}; + +struct spans_parm_close_ind { + spans_atm_conn clind_conn; /* Connection identity */ +}; + +struct spans_parm_close_rsp { + spans_atm_conn clrsp_conn; /* Connection identity */ + spans_result clrsp_result; /* Close result */ +}; + +struct spans_parm_close_cnf { + spans_atm_conn clcnf_conn; /* Connection identity */ + spans_result clcnf_result; /* Close result */ +}; + +struct spans_parm_rclose_req { + spans_atm_conn rcreq_conn; /* Connection identity */ +}; + +struct spans_parm_rclose_ind { + spans_atm_conn rcind_conn; /* Connection identity */ +}; + +struct spans_parm_rclose_rsp { + spans_atm_conn rcrsp_conn; /* Connection identity */ + spans_result rcrsp_result; /* Rclose result */ +}; + +struct spans_parm_rclose_cnf { + spans_atm_conn rccnf_conn; /* Connection identity */ + spans_result rccnf_result; /* Rclose result */ +}; + +struct spans_parm_multi_req { + spans_atm_conn mureq_conn; /* Connection identity */ + spans_aal mureq_aal; /* AAL type */ + spans_resrc mureq_desrsrc; /* Desired resources */ + spans_resrc mureq_minrsrc; /* Minimum resources */ + spans_vpvc mureq_vpvc; /* VPI/VCI preference */ +}; + +struct spans_parm_multi_ind { + spans_atm_conn muind_conn; /* Connection identity */ + spans_aal muind_aal; /* AAL type */ + spans_resrc muind_desrsrc; /* Desired resources */ + spans_resrc muind_minrsrc; /* Minimum resources */ + spans_vpvc muind_vpvc; /* VPI/VCI preference */ +}; + +struct spans_parm_multi_rsp { + spans_atm_conn mursp_conn; /* Connection identity */ + spans_result mursp_result; /* Multi result */ + spans_resrc mursp_rsrc; /* Allocated resources */ + spans_vpvc mursp_vpvc; /* Allocated VPI/VCI */ +}; + +struct spans_parm_multi_cnf { + spans_atm_conn mucnf_conn; /* Connection identity */ + spans_result mucnf_result; /* Multi result */ + spans_resrc mucnf_rsrc; /* Allocated resources */ + spans_vpvc mucnf_vpvc; /* Allocated VPI/VCI */ +}; + +struct spans_parm_add_req { + spans_atm_conn adreq_desconn; /* Desired connection identity */ + spans_atm_conn adreq_xstconn; /* Existing connection identity */ +}; + +struct spans_parm_add_ind { + spans_atm_conn adind_desconn; /* Desired connection identity */ + spans_atm_conn adind_xstconn; /* Existing connection identity */ +}; + +struct spans_parm_add_rsp { + spans_atm_conn adrsp_conn; /* Connection identity */ + spans_result adrsp_result; /* Add result */ + spans_resrc adrsp_rsrc; /* Allocated resources */ +}; + +struct spans_parm_add_cnf { + spans_atm_conn adcnf_conn; /* Connection identity */ + spans_result adcnf_result; /* Add result */ + spans_resrc adcnf_rsrc; /* Allocated resources */ +}; + +struct spans_parm_join_req { + spans_addr jnreq_addr; /* Group address */ +}; + +struct spans_parm_join_cnf { + spans_addr jncnf_addr; /* Group address */ + spans_result jncnf_result; /* Join result */ +}; + +struct spans_parm_leave_req { + spans_addr lvreq_addr; /* Group address */ +}; + +struct spans_parm_leave_cnf { + spans_addr lvcnf_addr; /* Group address */ + spans_result lvcnf_result; /* Leave result */ +}; + +struct spans_parm_vcir_ind { + u_int vrind_min; /* Lowest VCI available */ + u_int vrind_max; /* Highest VCI available */ +}; + +struct spans_parm_query_req { + spans_atm_conn qyreq_conn; /* Conn. being queried */ + spans_query_type qyreq_type; /* Query type */ +}; + +struct spans_parm_query_rsp { + spans_atm_conn qyrsp_conn; /* Conn. being queried */ + spans_query_type qyrsp_type; /* Query type */ + spans_conn_state qyrsp_state; /* Conn. state */ + u_int qyrsp_data; /* Extra state data */ +}; + + +/* + * Message Body + */ +union spans_msgbody switch (spans_msgtype mb_type) { + +case SPANS_STAT_REQ: spans_parm_stat_req mb_stat_req; +case SPANS_STAT_IND: spans_parm_stat_ind mb_stat_ind; +case SPANS_STAT_RSP: spans_parm_stat_rsp mb_stat_rsp; +case SPANS_OPEN_REQ: spans_parm_open_req mb_open_req; +case SPANS_OPEN_IND: spans_parm_open_ind mb_open_ind; +case SPANS_OPEN_RSP: spans_parm_open_rsp mb_open_rsp; +case SPANS_OPEN_CNF: spans_parm_open_cnf mb_open_cnf; +case SPANS_CLOSE_REQ: spans_parm_close_req mb_close_req; +case SPANS_CLOSE_IND: spans_parm_close_ind mb_close_ind; +case SPANS_CLOSE_RSP: spans_parm_close_rsp mb_close_rsp; +case SPANS_CLOSE_CNF: spans_parm_close_cnf mb_close_cnf; +case SPANS_RCLOSE_REQ: spans_parm_rclose_req mb_rclose_req; +case SPANS_RCLOSE_IND: spans_parm_rclose_ind mb_rclose_ind; +case SPANS_RCLOSE_RSP: spans_parm_rclose_rsp mb_rclose_rsp; +case SPANS_RCLOSE_CNF: spans_parm_rclose_cnf mb_rclose_cnf; +case SPANS_MULTI_REQ: spans_parm_multi_req mb_multi_req; +case SPANS_MULTI_IND: spans_parm_multi_ind mb_multi_ind; +case SPANS_MULTI_RSP: spans_parm_multi_rsp mb_multi_rsp; +case SPANS_MULTI_CNF: spans_parm_multi_cnf mb_multi_cnf; +case SPANS_ADD_REQ: spans_parm_add_req mb_add_req; +case SPANS_ADD_IND: spans_parm_add_ind mb_add_ind; +case SPANS_ADD_RSP: spans_parm_add_rsp mb_add_rsp; +case SPANS_ADD_CNF: spans_parm_add_cnf mb_add_cnf; +case SPANS_JOIN_REQ: spans_parm_join_req mb_join_req; +case SPANS_JOIN_CNF: spans_parm_join_cnf mb_join_cnf; +case SPANS_LEAVE_REQ: spans_parm_leave_req mb_leave_req; +case SPANS_LEAVE_CNF: spans_parm_leave_cnf mb_leave_cnf; +case SPANS_VCIR_IND: spans_parm_vcir_ind mb_vcir_ind; +case SPANS_QUERY_REQ: spans_parm_query_req mb_query_req; +case SPANS_QUERY_RSP: spans_parm_query_rsp mb_query_rsp; +}; + + +/* + * Message Format + */ +struct spans_msg { + spans_version sm_vers; + spans_msgbody sm_body; +}; + +#ifdef RPC_HDR +%#define sm_type sm_body.mb_type +%#define sm_stat_req sm_body.spans_msgbody_u.mb_stat_req +%#define sm_stat_ind sm_body.spans_msgbody_u.mb_stat_ind +%#define sm_stat_rsp sm_body.spans_msgbody_u.mb_stat_rsp +%#define sm_open_req sm_body.spans_msgbody_u.mb_open_req +%#define sm_open_ind sm_body.spans_msgbody_u.mb_open_ind +%#define sm_open_rsp sm_body.spans_msgbody_u.mb_open_rsp +%#define sm_open_cnf sm_body.spans_msgbody_u.mb_open_cnf +%#define sm_close_req sm_body.spans_msgbody_u.mb_close_req +%#define sm_close_ind sm_body.spans_msgbody_u.mb_close_ind +%#define sm_close_rsp sm_body.spans_msgbody_u.mb_close_rsp +%#define sm_close_cnf sm_body.spans_msgbody_u.mb_close_cnf +%#define sm_rclose_req sm_body.spans_msgbody_u.mb_rclose_req +%#define sm_rclose_ind sm_body.spans_msgbody_u.mb_rclose_ind +%#define sm_rclose_rsp sm_body.spans_msgbody_u.mb_rclose_rsp +%#define sm_rclose_cnf sm_body.spans_msgbody_u.mb_rclose_cnf +%#define sm_multi_req sm_body.spans_msgbody_u.mb_multi_req +%#define sm_multi_ind sm_body.spans_msgbody_u.mb_multi_ind +%#define sm_multi_rsp sm_body.spans_msgbody_u.mb_multi_rsp +%#define sm_multi_cnf sm_body.spans_msgbody_u.mb_multi_cnf +%#define sm_add_req sm_body.spans_msgbody_u.mb_add_req +%#define sm_add_ind sm_body.spans_msgbody_u.mb_add_ind +%#define sm_add_rsp sm_body.spans_msgbody_u.mb_add_rsp +%#define sm_add_cnf sm_body.spans_msgbody_u.mb_add_cnf +%#define sm_join_req sm_body.spans_msgbody_u.mb_join_req +%#define sm_join_cnf sm_body.spans_msgbody_u.mb_join_cnf +%#define sm_leave_req sm_body.spans_msgbody_u.mb_leave_req +%#define sm_leave_cnf sm_body.spans_msgbody_u.mb_leave_cnf +%#define sm_vcir_ind sm_body.spans_msgbody_u.mb_vcir_ind +%#define sm_query_req sm_body.spans_msgbody_u.mb_query_req +%#define sm_query_rsp sm_body.spans_msgbody_u.mb_query_rsp +#endif + +#ifdef RPC_HDR +%#endif /* _SPANS_SPANS_XDR_H */ +#endif diff --git a/sys/netatm/uni/Makefile b/sys/netatm/uni/Makefile new file mode 100644 index 0000000..5b769b4 --- /dev/null +++ b/sys/netatm/uni/Makefile @@ -0,0 +1,93 @@ +# +# +# =================================== +# 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. +# +# @(#) $Id: Makefile,v 1.6 1998/08/26 23:29:17 mks Exp $ +# +# + +# +# ATM Forum UNI Support +# --------------------- +# +# Source directory Makefile +# +# + +DEFS= + +UNI_HDRS= uni.h +UNI_SRCS= uni_load.c +UNI_OBJS= uni_load.o + +SIG_HDRS= unisig.h unisig_decode.h unisig_mbuf.h \ + unisig_msg.h unisig_print.h unisig_var.h +SIG_SRCS= unisig_decode.c unisig_encode.c unisig_if.c \ + unisig_mbuf.c unisig_msg.c \ + unisig_print.c unisig_proto.c \ + unisig_sigmgr_state.c unisig_subr.c \ + unisig_util.c unisig_vc_state.c +SIG_OBJS= unisig_decode.o unisig_encode.o unisig_if.o \ + unisig_mbuf.o unisig_msg.o \ + unisig_print.o unisig_proto.o \ + unisig_sigmgr_state.o unisig_subr.o \ + unisig_util.o unisig_vc_state.o + +SAAL_HDRS= sscop.h sscop_misc.h sscop_pdu.h sscop_var.h \ + sscf_uni.h sscf_uni_var.h +SAAL_SRCS= sscop.c sscop_lower.c sscop_pdu.c sscop_sigaa.c \ + sscop_sigcpcs.c sscop_subr.c sscop_timer.c sscop_upper.c \ + qsaal1_sigaa.c qsaal1_sigcpcs.c qsaal1_subr.c \ + q2110_sigaa.c q2110_sigcpcs.c q2110_subr.c \ + sscf_uni.c sscf_uni_lower.c sscf_uni_upper.c +SAAL_OBJS= sscop.o sscop_lower.o sscop_pdu.o sscop_sigaa.o \ + sscop_sigcpcs.o sscop_subr.o sscop_timer.o sscop_upper.o \ + qsaal1_sigaa.o qsaal1_sigcpcs.o qsaal1_subr.o \ + q2110_sigaa.o q2110_sigcpcs.o q2110_subr.o \ + sscf_uni.o sscf_uni_lower.o sscf_uni_upper.o + +IP_HDRS= uniip_var.h +IP_SRCS= uniip.c uniarp.c uniarp_cache.c uniarp_input.c \ + uniarp_output.c uniarp_timer.c uniarp_vcm.c +IP_OBJS= uniip.o uniarp.o uniarp_cache.o uniarp_input.o \ + uniarp_output.o uniarp_timer.o uniarp_vcm.o + +HDRS= $(UNI_HDRS) $(SIG_HDRS) $(SAAL_HDRS) $(IP_HDRS) +SRCS= $(UNI_SRCS) $(SIG_SRCS) $(SAAL_SRCS) $(IP_SRCS) +OBJS= $(UNI_OBJS) $(SIG_OBJS) $(SAAL_OBJS) $(IP_OBJS) +MOD= uni_mod.o + +OBJDIR= ../../`../../config/mkobjname -d`/uni + +all $(OBJS) $(MOD) config install clean depend lint load unload: + @if [ -d $(OBJDIR) ]; then \ + echo "cd $(OBJDIR); $(MAKE) $@"; \ + cd $(OBJDIR); \ + $(MAKE) $(MFLAGS) DEFS='$(DEFS)' HDRS='$(HDRS)' SRCS='$(SRCS)' OBJS='$(OBJS)' $@; \ + exit $$?; \ + else \ + echo "Object directory \"$(OBJDIR)\" does not exist."; \ + exit 1; \ + fi + diff --git a/sys/netatm/uni/q2110_sigaa.c b/sys/netatm/uni/q2110_sigaa.c new file mode 100644 index 0000000..357df71 --- /dev/null +++ b/sys/netatm/uni/q2110_sigaa.c @@ -0,0 +1,516 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: q2110_sigaa.c,v 1.6 1998/08/26 23:29:18 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * ITU-T Q.2110 - Process AA-signals (SAP_SSCOP) + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: q2110_sigaa.c,v 1.6 1998/08/26 23:29:18 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Local functions + */ +static void sscop_resreq_ready __P((struct sscop *, int, int)); +static void sscop_resrsp_inresyn __P((struct sscop *, int, int)); +static void sscop_recrsp_recovrsp __P((struct sscop *, int, int)); +static void sscop_recrsp_inrecov __P((struct sscop *, int, int)); + + +/* + * Stack command state lookup tables + */ +/* SSCOP_INIT */ +static void (*sscop_init_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + sscop_init_inst, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + NULL, /* SOS_OUTRECOV */ + NULL, /* SOS_RECOVRSP */ + NULL, /* SOS_INRECOV */ + NULL, /* SOS_READY */ + NULL /* SOS_TERM */ +}; + +/* SSCOP_TERM */ +static void (*sscop_term_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + sscop_term_all, /* SOS_INST */ + sscop_term_all, /* SOS_IDLE */ + sscop_term_all, /* SOS_OUTCONN */ + sscop_term_all, /* SOS_INCONN */ + sscop_term_all, /* SOS_OUTDISC */ + sscop_term_all, /* SOS_OUTRESYN */ + sscop_term_all, /* SOS_INRESYN */ + sscop_term_all, /* SOS_OUTRECOV */ + sscop_term_all, /* SOS_RECOVRSP */ + sscop_term_all, /* SOS_INRECOV */ + sscop_term_all, /* SOS_READY */ + sscop_term_all /* SOS_TERM */ +}; + +/* SSCOP_ESTABLISH_REQ */ +static void (*sscop_estreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + sscop_estreq_idle, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + sscop_estreq_idle, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + NULL, /* SOS_OUTRECOV */ + NULL, /* SOS_RECOVRSP */ + NULL, /* SOS_INRECOV */ + NULL, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_ESTABLISH_RSP */ +static void (*sscop_estrsp_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + sscop_estrsp_inconn, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + NULL, /* SOS_OUTRECOV */ + NULL, /* SOS_RECOVRSP */ + NULL, /* SOS_INRECOV */ + NULL, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_RELEASE_REQ */ +static void (*sscop_relreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + sscop_relreq_outconn, /* SOS_OUTCONN */ + sscop_relreq_inconn, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + sscop_relreq_outconn, /* SOS_OUTRESYN */ + sscop_relreq_outconn, /* SOS_INRESYN */ + sscop_relreq_ready, /* SOS_OUTRECOV */ + sscop_relreq_outconn, /* SOS_RECOVRSP */ + sscop_relreq_outconn, /* SOS_INRECOV */ + sscop_relreq_ready, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_DATA_REQ */ +static void (*sscop_datreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + sscop_aa_noop_1, /* SOS_OUTRECOV */ + NULL, /* SOS_RECOVRSP */ + NULL, /* SOS_INRECOV */ + sscop_datreq_ready, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_RESYNC_REQ */ +static void (*sscop_resreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + sscop_resreq_ready, /* SOS_OUTRECOV */ + sscop_resreq_ready, /* SOS_RECOVRSP */ + sscop_resreq_ready, /* SOS_INRECOV */ + sscop_resreq_ready, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_RESYNC_RSP */ +static void (*sscop_resrsp_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + sscop_resrsp_inresyn, /* SOS_INRESYN */ + NULL, /* SOS_OUTRECOV */ + NULL, /* SOS_RECOVRSP */ + NULL, /* SOS_INRECOV */ + NULL, /* SOS_READY */ + sscop_aa_noop_0 /* SOS_TERM */ +}; + +/* SSCOP_RECOVER_RSP */ +static void (*sscop_recrsp_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + NULL, /* SOS_OUTRECOV */ + sscop_recrsp_recovrsp, /* SOS_RECOVRSP */ + sscop_recrsp_inrecov, /* SOS_INRECOV */ + NULL, /* SOS_READY */ + sscop_aa_noop_0 /* SOS_TERM */ +}; + +/* SSCOP_UNITDATA_REQ */ +static void (*sscop_udtreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + sscop_udtreq_all, /* SOS_IDLE */ + sscop_udtreq_all, /* SOS_OUTCONN */ + sscop_udtreq_all, /* SOS_INCONN */ + sscop_udtreq_all, /* SOS_OUTDISC */ + sscop_udtreq_all, /* SOS_OUTRESYN */ + sscop_udtreq_all, /* SOS_INRESYN */ + sscop_udtreq_all, /* SOS_OUTRECOV */ + sscop_udtreq_all, /* SOS_RECOVRSP */ + sscop_udtreq_all, /* SOS_INRECOV */ + sscop_udtreq_all, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_RETRIEVE_REQ */ +static void (*sscop_retreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + NULL, /* SOS_OUTRECOV */ + NULL, /* SOS_RECOVRSP */ + NULL, /* SOS_INRECOV */ + NULL, /* SOS_READY */ + NULL /* SOS_TERM */ +}; + + +/* + * Stack command lookup table + */ +void (*(*sscop_q2110_aatab[SSCOP_CMD_SIZE])) + __P((struct sscop *, int, int)) = { + NULL, + sscop_init_tab, + sscop_term_tab, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + sscop_estreq_tab, + NULL, + sscop_estrsp_tab, + NULL, + sscop_relreq_tab, + NULL, + NULL, + sscop_datreq_tab, + NULL, + sscop_resreq_tab, + NULL, + sscop_resrsp_tab, + NULL, + NULL, + sscop_recrsp_tab, + sscop_udtreq_tab, + NULL, + sscop_retreq_tab, + NULL, + NULL +}; + + +/* + * SSCOP_RESYNC_REQ / SOS_READY Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing SSCOP-UU data + * arg2 unused + * + * Returns: + * none + * + */ +static void +sscop_resreq_ready(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * We don't support SSCOP-UU data + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Initialize receiver window + */ + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + + /* + * Send first RS PDU + */ + sop->so_connctl = 1; + SEQ_INCR(sop->so_sendconn, 1); + (void) sscop_send_rs(sop); + + /* + * Drain transmit and receive queues + */ + sscop_xmit_drain(sop); + sscop_rcvr_drain(sop); + + /* + * Set retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + /* + * Wait for RSAK + */ + sop->so_state = SOS_OUTRESYN; + + return; +} + + +/* + * SSCOP_RESYNC_RSP / SOS_INRESYN Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 unused + * arg2 unused + * + * Returns: + * none + * + */ +static void +sscop_resrsp_inresyn(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * Clear transmitter buffers + */ + q2110_clear_xmit(sop); + + /* + * Initialize state variables + */ + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + q2110_init_state(sop); + + /* + * Send RSAK PDU + */ + (void) sscop_send_rsak(sop); + + /* + * Start data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * Back to data transfer state + */ + sop->so_state = SOS_READY; + + return; +} + + +/* + * SSCOP_RECOVER_RSP / SOS_RECOVRSP Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 unused + * arg2 unused + * + * Returns: + * none + * + */ +static void +sscop_recrsp_recovrsp(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * Clear transmitter buffers, if not done earlier + */ + if (sop->so_flags & SOF_NOCLRBUF) + q2110_clear_xmit(sop); + + /* + * Initialize state variables + */ + q2110_init_state(sop); + + /* + * Start data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * Back to data transfer state + */ + sop->so_state = SOS_READY; + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; +} + + +/* + * SSCOP_RECOVER_RSP / SOS_INRECOV Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 unused + * arg2 unused + * + * Returns: + * none + * + */ +static void +sscop_recrsp_inrecov(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * Clear transmitter buffers, if not done earlier + */ + if (sop->so_flags & SOF_NOCLRBUF) + q2110_clear_xmit(sop); + + /* + * Initialize state variables + */ + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + q2110_init_state(sop); + + /* + * Send ERAK PDU + */ + (void) sscop_send_erak(sop); + + /* + * Start data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * Back to data transfer state + */ + sop->so_state = SOS_READY; + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; +} + diff --git a/sys/netatm/uni/q2110_sigcpcs.c b/sys/netatm/uni/q2110_sigcpcs.c new file mode 100644 index 0000000..0fa5555 --- /dev/null +++ b/sys/netatm/uni/q2110_sigcpcs.c @@ -0,0 +1,1760 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: q2110_sigcpcs.c,v 1.7 1998/08/26 23:29:18 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * ITU-T Q.2110 - Process CPCS-signals (SSCOP PDUs) + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: q2110_sigcpcs.c,v 1.7 1998/08/26 23:29:18 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Local functions + */ +static void sscop_bgn_outconn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_bgn_inconn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_bgn_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_bgrej_outrecov __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_end_outrecov __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_end_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_endak_outrecov __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_rs_outresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_rs_inresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_rs_outrecov __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_rs_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_er_error __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_er_idle __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_er_outrecov __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_er_recovrsp __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_er_inrecov __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_er_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_erak_error __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_erak_idle __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_erak_outrecov __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_sd_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_poll_ready __P((struct sscop *, KBuffer *, caddr_t)); + + +/* + * PDU type state lookup tables + */ +/* BGN PDU */ +static void (*sscop_bgn_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_bgn_idle, /* SOS_IDLE */ + sscop_bgn_outconn, /* SOS_OUTCONN */ + sscop_bgn_inconn, /* SOS_INCONN */ + sscop_bgn_outdisc, /* SOS_OUTDISC */ + sscop_bgn_outresyn, /* SOS_OUTRESYN */ + sscop_bgn_inresyn, /* SOS_INRESYN */ + sscop_bgn_inresyn, /* SOS_OUTRECOV */ + sscop_bgn_inresyn, /* SOS_RECOVRSP */ + sscop_bgn_inresyn, /* SOS_INRECOV */ + sscop_bgn_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* BGAK PDU */ +static void (*sscop_bgak_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_bgak_idle, /* SOS_IDLE */ + sscop_bgak_outconn, /* SOS_OUTCONN */ + sscop_bgak_error, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_noop, /* SOS_OUTRESYN */ + sscop_bgak_error, /* SOS_INRESYN */ + sscop_bgak_error, /* SOS_OUTRECOV */ + sscop_bgak_error, /* SOS_RECOVRSP */ + sscop_bgak_error, /* SOS_INRECOV */ + sscop_noop, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* BGREJ PDU */ +static void (*sscop_bgrej_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_bgrej_error, /* SOS_IDLE */ + sscop_bgrej_outconn, /* SOS_OUTCONN */ + sscop_bgrej_inconn, /* SOS_INCONN */ + sscop_endak_outdisc, /* SOS_OUTDISC */ + sscop_bgrej_outresyn, /* SOS_OUTRESYN */ + sscop_bgrej_inconn, /* SOS_INRESYN */ + sscop_bgrej_outrecov, /* SOS_OUTRECOV */ + sscop_bgrej_inconn, /* SOS_RECOVRSP */ + sscop_bgrej_inconn, /* SOS_INRECOV */ + sscop_bgrej_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* END PDU */ +static void (*sscop_end_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_end_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_end_inconn, /* SOS_INCONN */ + sscop_end_outdisc, /* SOS_OUTDISC */ + sscop_end_inconn, /* SOS_OUTRESYN */ + sscop_end_inconn, /* SOS_INRESYN */ + sscop_end_outrecov, /* SOS_OUTRECOV */ + sscop_end_inconn, /* SOS_RECOVRSP */ + sscop_end_inconn, /* SOS_INRECOV */ + sscop_end_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* ENDAK PDU */ +static void (*sscop_endak_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_noop, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_endak_inconn, /* SOS_INCONN */ + sscop_endak_outdisc, /* SOS_OUTDISC */ + sscop_endak_inconn, /* SOS_OUTRESYN */ + sscop_endak_inconn, /* SOS_INRESYN */ + sscop_endak_outrecov, /* SOS_OUTRECOV */ + sscop_endak_inconn, /* SOS_RECOVRSP */ + sscop_endak_inconn, /* SOS_INRECOV */ + sscop_endak_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* RS PDU */ +static void (*sscop_rs_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_rs_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_rs_error, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_rs_outresyn, /* SOS_OUTRESYN */ + sscop_rs_inresyn, /* SOS_INRESYN */ + sscop_rs_outrecov, /* SOS_OUTRECOV */ + sscop_rs_outrecov, /* SOS_RECOVRSP */ + sscop_rs_outrecov, /* SOS_INRECOV */ + sscop_rs_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* RSAK PDU */ +static void (*sscop_rsak_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_rsak_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_rsak_error, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_rsak_outresyn, /* SOS_OUTRESYN */ + sscop_rsak_error, /* SOS_INRESYN */ + sscop_rsak_error, /* SOS_OUTRECOV */ + sscop_rsak_error, /* SOS_RECOVRSP */ + sscop_rsak_error, /* SOS_INRECOV */ + sscop_noop, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* ER PDU */ +static void (*sscop_er_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_er_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_er_error, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_noop, /* SOS_OUTRESYN */ + sscop_er_error, /* SOS_INRESYN */ + sscop_er_outrecov, /* SOS_OUTRECOV */ + sscop_er_recovrsp, /* SOS_RECOVRSP */ + sscop_er_inrecov, /* SOS_INRECOV */ + sscop_er_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* ERAK PDU */ +static void (*sscop_erak_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_erak_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_erak_error, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_noop, /* SOS_OUTRESYN */ + sscop_erak_error, /* SOS_INRESYN */ + sscop_erak_outrecov, /* SOS_OUTRECOV */ + sscop_noop, /* SOS_RECOVRSP */ + sscop_erak_error, /* SOS_INRECOV */ + sscop_noop, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* SD PDU */ +static void (*sscop_sd_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_sd_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_sd_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_noop, /* SOS_OUTRESYN */ + sscop_sd_inconn, /* SOS_INRESYN */ + sscop_noop, /* SOS_OUTRECOV */ + sscop_noop, /* SOS_RECOVRSP */ + sscop_sd_inconn, /* SOS_INRECOV */ + sscop_sd_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* POLL PDU */ +static void (*sscop_poll_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_poll_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_poll_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_noop, /* SOS_OUTRESYN */ + sscop_poll_inconn, /* SOS_INRESYN */ + sscop_noop, /* SOS_OUTRECOV */ + sscop_noop, /* SOS_RECOVRSP */ + sscop_poll_inconn, /* SOS_INRECOV */ + sscop_poll_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* STAT PDU */ +static void (*sscop_stat_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_stat_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_stat_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_noop, /* SOS_OUTRESYN */ + sscop_stat_inconn, /* SOS_INRESYN */ + sscop_noop, /* SOS_OUTRECOV */ + sscop_stat_inconn, /* SOS_RECOVRSP */ + sscop_stat_inconn, /* SOS_INRECOV */ + sscop_stat_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* USTAT PDU */ +static void (*sscop_ustat_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_ustat_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_ustat_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_noop, /* SOS_OUTRESYN */ + sscop_ustat_inconn, /* SOS_INRESYN */ + sscop_noop, /* SOS_OUTRECOV */ + sscop_ustat_inconn, /* SOS_RECOVRSP */ + sscop_ustat_inconn, /* SOS_INRECOV */ + sscop_ustat_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* UD PDU */ +static void (*sscop_ud_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_ud_all, /* SOS_IDLE */ + sscop_ud_all, /* SOS_OUTCONN */ + sscop_ud_all, /* SOS_INCONN */ + sscop_ud_all, /* SOS_OUTDISC */ + sscop_ud_all, /* SOS_OUTRESYN */ + sscop_ud_all, /* SOS_INRESYN */ + sscop_ud_all, /* SOS_OUTRECOV */ + sscop_ud_all, /* SOS_RECOVRSP */ + sscop_ud_all, /* SOS_INRECOV */ + sscop_ud_all, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* MD PDU */ +static void (*sscop_md_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_md_all, /* SOS_IDLE */ + sscop_md_all, /* SOS_OUTCONN */ + sscop_md_all, /* SOS_INCONN */ + sscop_md_all, /* SOS_OUTDISC */ + sscop_md_all, /* SOS_OUTRESYN */ + sscop_md_all, /* SOS_INRESYN */ + sscop_md_all, /* SOS_OUTRECOV */ + sscop_md_all, /* SOS_RECOVRSP */ + sscop_md_all, /* SOS_INRECOV */ + sscop_md_all, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + + +/* + * PDU type lookup table + */ +void (*(*sscop_q2110_pdutab[])) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, + sscop_bgn_tab, + sscop_bgak_tab, + sscop_end_tab, + sscop_endak_tab, + sscop_rs_tab, + sscop_rsak_tab, + sscop_bgrej_tab, + sscop_sd_tab, + sscop_er_tab, + sscop_poll_tab, + sscop_stat_tab, + sscop_ustat_tab, + sscop_ud_tab, + sscop_md_tab, + sscop_erak_tab +}; + + +/* + * BGN PDU / SOS_OUTCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_bgn_outconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct bgn_pdu *bp = (struct bgn_pdu *)trlr; + int err; + + /* + * If retransmitted BGN, ignore it + */ + if (sscop_is_rexmit(sop, bp->bgn_nsq)) { + KB_FREEALL(m); + return; + } + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Initialize state variables + */ + SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + q2110_init_state(sop); + + /* + * Return an ACK to peer + */ + (void) sscop_send_bgak(sop); + + /* + * Notify user of connection establishment + */ + STACK_CALL(SSCOP_ESTABLISH_CNF, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Start data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * OK, we're ready for data + */ + sop->so_state = SOS_READY; + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; +} + + +/* + * BGN PDU / SOS_INCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_bgn_inconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct bgn_pdu *bp = (struct bgn_pdu *)trlr; + int err; + + /* + * If retransmitted BGN, ignore it + */ + if (sscop_is_rexmit(sop, bp->bgn_nsq)) { + KB_FREEALL(m); + return; + } + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); + + /* + * First, tell user current connection has been released + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Now, tell user of new connection establishment + */ + STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + return; +} + + +/* + * BGN PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_bgn_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct bgn_pdu *bp = (struct bgn_pdu *)trlr; + int err; + + /* + * If retransmitted BGN, just ACK it again + */ + if (sscop_is_rexmit(sop, bp->bgn_nsq)) { + KB_FREEALL(m); + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + (void) sscop_send_bgak(sop); + return; + } + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); + + /* + * Clear out appropriate queues + */ + q2110_prep_retrieve(sop); + + /* + * Tell user current connection has been released + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Tell user of incoming connection + */ + STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Wait for user's response + */ + sop->so_state = SOS_INCONN; + + return; +} + + +/* + * BGREJ PDU / SOS_OUTRECOV Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_bgrej_outrecov(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Report protocol error + */ + sscop_bgrej_error(sop, m, trlr); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Clear receiver buffer + */ + sscop_rcvr_drain(sop); + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * END PDU / SOS_OUTRECOV Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_end_outrecov(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct end_pdu *ep = (struct end_pdu *)trlr; + int err, source; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Acknowledge END + */ + (void) sscop_send_endak(sop); + + /* + * Get Source value + */ + if (ep->end_type & PT_SOURCE_SSCOP) + source = SSCOP_SOURCE_SSCOP; + else + source = SSCOP_SOURCE_USER; + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Clear receiver buffer + */ + sscop_rcvr_drain(sop); + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * END PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_end_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct end_pdu *ep = (struct end_pdu *)trlr; + int err, source; + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Acknowledge END + */ + (void) sscop_send_endak(sop); + + /* + * Get Source value + */ + if (ep->end_type & PT_SOURCE_SSCOP) + source = SSCOP_SOURCE_SSCOP; + else + source = SSCOP_SOURCE_USER; + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Clear out appropriate queues + */ + q2110_prep_retrieve(sop); + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * ENDAK PDU / SOS_OUTRECOV Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_endak_outrecov(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Report protocol error + */ + sscop_endak_error(sop, m, trlr); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Clear receiver buffer + */ + sscop_rcvr_drain(sop); + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * RS PDU / SOS_OUTRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_rs_outresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct rs_pdu *rp = (struct rs_pdu *)trlr; + int err; + + /* + * If retransmitted RS, ignore it + */ + if (sscop_is_rexmit(sop, rp->rs_nsq)) { + KB_FREEALL(m); + return; + } + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Initialize state variables + */ + SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr)); + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + q2110_init_state(sop); + + /* + * Free PDU buffers + */ + KB_FREEALL(m); + + /* + * Return an ACK to peer + */ + (void) sscop_send_rsak(sop); + + /* + * Notify user of connection resynchronization + */ + STACK_CALL(SSCOP_RESYNC_CNF, sop->so_upper, sop->so_toku, + sop->so_connvc, 0, 0, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Start data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * OK, we're ready for data + */ + sop->so_state = SOS_READY; + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; +} + + +/* + * RS PDU / SOS_INRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_rs_inresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct rs_pdu *rp = (struct rs_pdu *)trlr; + + /* + * If retransmitted RS, ignore it + */ + if (sscop_is_rexmit(sop, rp->rs_nsq)) { + KB_FREEALL(m); + return; + } + + /* + * Report error condition + */ + sscop_rs_error(sop, m, trlr); + + return; +} + + +/* + * RS PDU / SOS_OUTRECOV Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_rs_outrecov(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct rs_pdu *rp = (struct rs_pdu *)trlr; + int err; + + /* + * If retransmitted RS, report an error + */ + if (sscop_is_rexmit(sop, rp->rs_nsq)) { + sscop_rs_error(sop, m, trlr); + return; + } + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr)); + + /* + * Notify user of connection resynchronization + */ + STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Clear receiver buffer + */ + sscop_rcvr_drain(sop); + + /* + * Wait for user response + */ + sop->so_state = SOS_INRESYN; + + return; +} + + +/* + * RS PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_rs_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct rs_pdu *rp = (struct rs_pdu *)trlr; + int err; + + /* + * If retransmitted RS, just ACK it + */ + if (sscop_is_rexmit(sop, rp->rs_nsq)) { + KB_FREEALL(m); + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + sscop_send_rsak(sop); + return; + } + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(rp->rs_nmr)); + + /* + * Notify user of connection resynchronization + */ + STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Clear out appropriate queues + */ + q2110_prep_retrieve(sop); + + /* + * Wait for user response + */ + sop->so_state = SOS_INRESYN; + + return; +} + +/* + * ER PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_er_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'L'); + KB_FREEALL(m); + + return; +} + + +/* + * ER PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_er_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_er_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + return; +} + + +/* + * ER PDU / SOS_OUTRECOV Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_er_outrecov(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct er_pdu *ep = (struct er_pdu *)trlr; + int err; + + /* + * If retransmitted ER, report an error + */ + if (sscop_is_rexmit(sop, ep->er_nsq)) { + sscop_er_error(sop, m, trlr); + return; + } + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(ep->er_nmr)); + + /* + * Initialize receiver window + */ + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + + /* + * Free PDU buffers + */ + KB_FREEALL(m); + + /* + * Acknowledge ER + */ + (void) sscop_send_erak(sop); + + /* + * Deliver any outstanding data to user + */ + q2110_deliver_data(sop); + + /* + * Notify user of connection recovery + */ + STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, 0, 0, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Wait for user response + */ + sop->so_state = SOS_RECOVRSP; + + return; +} + + +/* + * ER PDU / SOS_RECOVRSP Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_er_recovrsp(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct er_pdu *ep = (struct er_pdu *)trlr; + + /* + * If retransmitted ER, just ACK it + */ + if (sscop_is_rexmit(sop, ep->er_nsq)) { + KB_FREEALL(m); + (void) sscop_send_erak(sop); + return; + } + + /* + * Report error condition + */ + sscop_er_error(sop, m, trlr); + + return; +} + + +/* + * ER PDU / SOS_INRECOV Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_er_inrecov(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct er_pdu *ep = (struct er_pdu *)trlr; + + /* + * If retransmitted ER, just ignore it + */ + if (sscop_is_rexmit(sop, ep->er_nsq)) { + KB_FREEALL(m); + return; + } + + /* + * Report error condition + */ + sscop_er_error(sop, m, trlr); + + return; +} + + +/* + * ER PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_er_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct er_pdu *ep = (struct er_pdu *)trlr; + int err; + + /* + * If retransmitted ER, just ACK it + */ + if (sscop_is_rexmit(sop, ep->er_nsq)) { + KB_FREEALL(m); + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + sscop_send_erak(sop); + return; + } + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(ep->er_nmr)); + + /* + * Free PDU buffers + */ + KB_FREEALL(m); + + /* + * Clear out appropriate queues + */ + q2110_prep_recovery(sop); + + /* + * Deliver any outstanding data to user + */ + q2110_deliver_data(sop); + + /* + * Notify user of connection recovery + */ + STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, 0, 0, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Wait for user response + */ + sop->so_state = SOS_INRECOV; + + return; +} + + +/* + * ERAK PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_erak_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'M'); + KB_FREEALL(m); + + return; +} + + +/* + * ERAK PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_erak_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_erak_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + return; +} + + +/* + * ERAK PDU / SOS_OUTRECOV Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_erak_outrecov(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct erak_pdu *ep = (struct erak_pdu *)trlr; + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(ep->erak_nmr)); + + /* + * Free PDU buffers + */ + KB_FREEALL(m); + + /* + * Deliver any outstanding data to user + */ + q2110_deliver_data(sop); + + /* + * Notify user of connection recovery + */ + STACK_CALL(SSCOP_RECOVER_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, 0, 0, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Wait for user response + */ + sop->so_state = SOS_RECOVRSP; + + return; +} + + +/* + * SD PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_sd_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct sd_pdu *sp = (struct sd_pdu *)trlr; + struct pdu_hdr *php; + KBuffer *n; + sscop_seq ns; + int err, space; + + /* + * Get PDU sequence number + */ + SEQ_SET(ns, ntohl(sp->sd_ns)); + + /* + * Ensure that the sequence number fits within the window + */ + if (SEQ_GEQ(ns, sop->so_rcvmax, sop->so_rcvnext)) { + /* + * It doesn't, drop received data + */ + KB_FREEALL(m); + + /* + * If next highest PDU hasn't reached window end yet, + * then send a USTAT to inform transmitter of this gap + */ + if (SEQ_LT(sop->so_rcvhigh, sop->so_rcvmax, sop->so_rcvnext)) { + (void) sscop_send_ustat(sop, sop->so_rcvmax); + sop->so_rcvhigh = sop->so_rcvmax; + } + return; + } + + /* + * If this is the next in-sequence PDU, hand it to user + */ + if (ns == sop->so_rcvnext) { + STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, ns, err); + if (err) { + KB_FREEALL(m); + return; + } + + /* + * Bump next expected sequence number + */ + SEQ_INCR(sop->so_rcvnext, 1); + + /* + * Slide receive window down + */ + SEQ_INCR(sop->so_rcvmax, 1); + + /* + * Is this the highest sequence PDU we've received?? + */ + if (ns == sop->so_rcvhigh) { + /* + * Yes, bump the limit and exit + */ + sop->so_rcvhigh = sop->so_rcvnext; + return; + } + + /* + * This is a retransmitted PDU, so see if we have + * more in-sequence PDUs already queued up + */ + while ((php = sop->so_recv_hd) && + (php->ph_ns == sop->so_rcvnext)) { + + /* + * Yup we do, so remove next PDU from queue and + * pass it up to the user as well + */ + sop->so_recv_hd = php->ph_recv_lk; + if (sop->so_recv_hd == NULL) + sop->so_recv_tl = NULL; + STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)php->ph_buf, php->ph_ns, + err); + if (err) { + /* + * Should never happen, but... + */ + KB_FREEALL(php->ph_buf); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Bump next expected sequence number + */ + SEQ_INCR(sop->so_rcvnext, 1); + + /* + * Slide receive window down + */ + SEQ_INCR(sop->so_rcvmax, 1); + } + + /* + * Finished with data delivery... + */ + return; + } + + /* + * We're gonna have to queue this PDU, so find space + * for the PDU header + */ + KB_HEADROOM(m, space); + + /* + * If there's not enough room in the received buffer, + * allocate & link a new buffer for the header + */ + if (space < sizeof(struct pdu_hdr)) { + + KB_ALLOC(n, sizeof(struct pdu_hdr), KB_F_NOWAIT, KB_T_HEADER); + if (n == NULL) { + KB_FREEALL(m); + return; + } + KB_HEADSET(n, sizeof(struct pdu_hdr)); + KB_LEN(n) = 0; + KB_LINKHEAD(n, m); + m = n; + } + + /* + * Build PDU header + * + * We can at least assume/require that the start of + * the user data is aligned. Also note that we don't + * include this header in the buffer len/offset fields. + */ + KB_DATASTART(m, php, struct pdu_hdr *); + php--; + php->ph_ns = ns; + php->ph_buf = m; + + /* + * Insert PDU into the receive queue + */ + if (sscop_recv_insert(sop, php)) { + /* + * Oops, a duplicate sequence number PDU is already on + * the queue, somethings wrong here. + */ + sscop_maa_error(sop, 'Q'); + + /* + * Free buffers + */ + KB_FREEALL(m); + + /* + * Go into recovery mode + */ + q2110_error_recovery(sop); + + return; + } + + /* + * Are we at the high-water mark?? + */ + if (ns == sop->so_rcvhigh) { + /* + * Yes, just bump the mark + */ + SEQ_INCR(sop->so_rcvhigh, 1); + + return; + } + + /* + * Are we beyond the high-water mark?? + */ + if (SEQ_GT(ns, sop->so_rcvhigh, sop->so_rcvnext)) { + /* + * Yes, then there's a missing PDU, so inform the transmitter + */ + (void) sscop_send_ustat(sop, ns); + + /* + * Update high-water mark + */ + sop->so_rcvhigh = SEQ_ADD(ns, 1); + } + + return; +} + + +/* + * POLL PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_poll_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct poll_pdu *pp = (struct poll_pdu *)trlr; + sscop_seq nps; + + NTOHL(pp->poll_ns); + + /* + * If the poll sequence number is less than highest number + * we've already seen, something's wrong + */ + if (SEQ_LT(pp->poll_ns, sop->so_rcvhigh, sop->so_rcvnext)) { + /* + * Record error condition + */ + sscop_maa_error(sop, 'Q'); + + /* + * Free buffers + */ + KB_FREEALL(m); + + /* + * Go into recovery mode + */ + q2110_error_recovery(sop); + + return; + } + + /* + * Set a new "next highest" sequence number expected + */ + if (SEQ_LT(pp->poll_ns, sop->so_rcvmax, sop->so_rcvnext)) + SEQ_SET(sop->so_rcvhigh, pp->poll_ns); + else + sop->so_rcvhigh = sop->so_rcvmax; + + /* + * Return a STAT PDU to peer + */ + SEQ_SET(nps, ntohl(pp->poll_nps)); + KB_FREEALL(m); + (void) sscop_send_stat(sop, nps); + + return; +} + diff --git a/sys/netatm/uni/q2110_subr.c b/sys/netatm/uni/q2110_subr.c new file mode 100644 index 0000000..4c6036b --- /dev/null +++ b/sys/netatm/uni/q2110_subr.c @@ -0,0 +1,239 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: q2110_subr.c,v 1.1 1998/04/07 23:15:20 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * ITU-T Q.2110 - Subroutines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: q2110_subr.c,v 1.1 1998/04/07 23:15:20 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Conditionally Clear Transmission Queues + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +q2110_clear_xmit(sop) + struct sscop *sop; +{ + /* + * Only clear queues if 'Clear Buffers' == No + */ + if (sop->so_flags & SOF_NOCLRBUF) + sscop_xmit_drain(sop); +} + + +/* + * Initialize Data Transfer State Variables + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +q2110_init_state(sop) + struct sscop *sop; +{ + /* + * Initialize for entry into Data Transfer Ready state + */ + sop->so_send = 0; + sop->so_pollsend = 0; + sop->so_ack = 0; + sop->so_pollack = 1; + sop->so_polldata = 0; + sop->so_rcvhigh = 0; + sop->so_rcvnext = 0; +} + + +/* + * Prepare Queues for Data Retrieval + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +q2110_prep_retrieve(sop) + struct sscop *sop; +{ + /* + * If 'Clear Buffers' == No, just clear retransmit queue, + * else clear all transmission queues + */ + if (sop->so_flags & SOF_NOCLRBUF) { + sop->so_rexmit_hd = NULL; + sop->so_rexmit_tl = NULL; + } else + sscop_xmit_drain(sop); + + /* + * Clear receiver queue + */ + sscop_rcvr_drain(sop); +} + + +/* + * Prepare Queues for Error Recovery + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +q2110_prep_recovery(sop) + struct sscop *sop; +{ + /* + * If 'Clear Buffers' == No, just clear retransmit queue, + * else clear all transmission queues + */ + if (sop->so_flags & SOF_NOCLRBUF) { + sop->so_rexmit_hd = NULL; + sop->so_rexmit_tl = NULL; + } else + sscop_xmit_drain(sop); +} + + +/* + * Conditionally Deliver Received Data to User + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +q2110_deliver_data(sop) + struct sscop *sop; +{ + /* + * If 'Clear Buffers' == No, give data to user + */ + if (sop->so_flags & SOF_NOCLRBUF) { + /* + * We don't support 'Clear Buffers' == No, so don't bother + */ + } + + /* + * Clear receiver queue + */ + sscop_rcvr_drain(sop); +} + + +/* + * Enter Connection Recovery Mode + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +q2110_error_recovery(sop) + struct sscop *sop; +{ + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Initialize receiver window + */ + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + + /* + * Send first ER PDU + */ + sop->so_connctl = 1; + SEQ_INCR(sop->so_sendconn, 1); + (void) sscop_send_er(sop); + + /* + * Set retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + /* + * Clear out appropriate queues + */ + q2110_prep_recovery(sop); + + /* + * Wait for ERAK + */ + sop->so_state = SOS_OUTRECOV; + + return; +} + diff --git a/sys/netatm/uni/qsaal1_sigaa.c b/sys/netatm/uni/qsaal1_sigaa.c new file mode 100644 index 0000000..f3b0097 --- /dev/null +++ b/sys/netatm/uni/qsaal1_sigaa.c @@ -0,0 +1,518 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: qsaal1_sigaa.c,v 1.7 1998/08/26 23:29:18 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * ITU-T Q.SAAL1 - Process AA-signals (SAP_SSCOP) + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: qsaal1_sigaa.c,v 1.7 1998/08/26 23:29:18 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Local functions + */ +static void sscop_estreq_ready __P((struct sscop *, int, int)); +static void sscop_datreq_outconn __P((struct sscop *, int, int)); +static void sscop_resreq_ready __P((struct sscop *, int, int)); +static void sscop_resrsp_inresyn __P((struct sscop *, int, int)); +static void sscop_resrsp_conresyn __P((struct sscop *, int, int)); + + +/* + * Stack command state lookup tables + */ +/* SSCOP_INIT */ +static void (*sscop_init_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + sscop_init_inst, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + NULL, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + NULL, /* SOS_READY */ + NULL /* SOS_TERM */ +}; + +/* SSCOP_TERM */ +static void (*sscop_term_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + sscop_term_all, /* SOS_INST */ + sscop_term_all, /* SOS_IDLE */ + sscop_term_all, /* SOS_OUTCONN */ + sscop_term_all, /* SOS_INCONN */ + sscop_term_all, /* SOS_OUTDISC */ + sscop_term_all, /* SOS_OUTRESYN */ + sscop_term_all, /* SOS_INRESYN */ + sscop_term_all, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_term_all, /* SOS_READY */ + sscop_term_all /* SOS_TERM */ +}; + +/* SSCOP_ESTABLISH_REQ */ +static void (*sscop_estreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + sscop_estreq_idle, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + sscop_estreq_ready, /* SOS_OUTDISC */ + sscop_estreq_ready, /* SOS_OUTRESYN */ + sscop_estreq_ready, /* SOS_INRESYN */ + sscop_estreq_ready, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_estreq_ready, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_ESTABLISH_RSP */ +static void (*sscop_estrsp_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + sscop_estrsp_inconn, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + NULL, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_aa_noop_1, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_RELEASE_REQ */ +static void (*sscop_relreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + sscop_relreq_outconn, /* SOS_OUTCONN */ + sscop_relreq_inconn, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + sscop_relreq_outconn, /* SOS_OUTRESYN */ + sscop_relreq_ready, /* SOS_INRESYN */ + sscop_relreq_outconn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_relreq_ready, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_DATA_REQ */ +static void (*sscop_datreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + sscop_datreq_outconn, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + sscop_datreq_ready, /* SOS_INRESYN */ + NULL, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_datreq_ready, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_RESYNC_REQ */ +static void (*sscop_resreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + NULL, /* SOS_INRESYN */ + NULL, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_resreq_ready, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + +/* SSCOP_RESYNC_RSP */ +static void (*sscop_resrsp_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + NULL, /* SOS_IDLE */ + NULL, /* SOS_OUTCONN */ + NULL, /* SOS_INCONN */ + NULL, /* SOS_OUTDISC */ + NULL, /* SOS_OUTRESYN */ + sscop_resrsp_inresyn, /* SOS_INRESYN */ + sscop_resrsp_conresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + NULL, /* SOS_READY */ + sscop_aa_noop_0 /* SOS_TERM */ +}; + +/* SSCOP_UNITDATA_REQ */ +static void (*sscop_udtreq_tab[SOS_NUMSTATES]) + __P((struct sscop *, int, int)) = { + NULL, /* SOS_INST */ + sscop_udtreq_all, /* SOS_IDLE */ + sscop_udtreq_all, /* SOS_OUTCONN */ + sscop_udtreq_all, /* SOS_INCONN */ + sscop_udtreq_all, /* SOS_OUTDISC */ + sscop_udtreq_all, /* SOS_OUTRESYN */ + sscop_udtreq_all, /* SOS_INRESYN */ + sscop_udtreq_all, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_udtreq_all, /* SOS_READY */ + sscop_aa_noop_1 /* SOS_TERM */ +}; + + +/* + * Stack command lookup table + */ +void (*(*sscop_qsaal_aatab[SSCOP_CMD_SIZE])) + __P((struct sscop *, int, int)) = { + NULL, + sscop_init_tab, + sscop_term_tab, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + sscop_estreq_tab, + NULL, + sscop_estrsp_tab, + NULL, + sscop_relreq_tab, + NULL, + NULL, + sscop_datreq_tab, + NULL, + sscop_resreq_tab, + NULL, + sscop_resrsp_tab, + NULL, + NULL, + NULL, + sscop_udtreq_tab, + NULL, + NULL, + NULL, + NULL +}; + + +/* + * SSCOP_ESTABLISH_REQ / SOS_READY Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing SSCOP-UU data + * arg2 buffer release parameter + * + * Returns: + * none + * + */ +static void +sscop_estreq_ready(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * We don't support SSCOP-UU data + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * We currently only support BR=YES + */ + if (arg2 != SSCOP_BR_YES) { + sscop_abort(sop, "sscop: BR != YES\n"); + return; + } + + /* + * Stop poll timer + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Stop lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = 0; + + /* + * Initialize receiver window + */ + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + + /* + * Send first BGN PDU + */ + sop->so_connctl = 1; + (void) sscop_send_bgn(sop, SSCOP_SOURCE_USER); + + /* + * Reset transmitter state + */ + qsaal1_reset_xmit(sop); + + /* + * Set retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + /* + * Wait for BGAK + */ + sop->so_state = SOS_OUTCONN; + + return; +} + + +/* + * SSCOP_DATA_REQ / SOS_OUTCONN Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing assured user data + * arg2 unused + * + * Returns: + * none + * + */ +static void +sscop_datreq_outconn(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + KBuffer *m = (KBuffer *)arg1; + + /* + * We must have a buffer (even if it contains no data) + */ + if (m == NULL) { + sscop_abort(sop, "sscop_datreq_outconn: no buffer\n"); + return; + } + + /* + * Only accept data here if in the middle of an SSCOP-initiated + * session reestablishment + */ + if ((sop->so_flags & SOF_REESTAB) == 0) { + KB_FREEALL(m); + sscop_abort(sop, "sscop_datreq_outconn: data not allowed\n"); + return; + } + + /* + * Place data at end of transmission queue + */ + KB_QNEXT(m) = NULL; + if (sop->so_xmit_hd == NULL) + sop->so_xmit_hd = m; + else + KB_QNEXT(sop->so_xmit_tl) = m; + sop->so_xmit_tl = m; + + /* + * Note that the transmit queues need to be serviced + */ + sop->so_flags |= SOF_XMITSRVC; + + return; +} + + +/* + * SSCOP_RESYNC_REQ / SOS_READY Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing SSCOP-UU data + * arg2 unused + * + * Returns: + * none + * + */ +static void +sscop_resreq_ready(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * We don't support SSCOP-UU data + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * Stop poll timer + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Stop lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = 0; + + /* + * Send first RS PDU + */ + sop->so_connctl = 1; + (void) sscop_send_rs(sop); + + /* + * Reset transmitter state + */ + qsaal1_reset_xmit(sop); + + /* + * Set retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + /* + * Wait for RSAK + */ + sop->so_state = SOS_OUTRESYN; + + return; +} + + +/* + * SSCOP_RESYNC_RSP / SOS_INRESYN Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 unused + * arg2 unused + * + * Returns: + * none + * + */ +static void +sscop_resrsp_inresyn(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * Send RSAK PDU + */ + (void) sscop_send_rsak(sop); + + /* + * Back to data transfer state + */ + sop->so_state = SOS_READY; + + return; +} + + +/* + * SSCOP_RESYNC_RSP / SOS_CONRESYN Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 unused + * arg2 unused + * + * Returns: + * none + * + */ +static void +sscop_resrsp_conresyn(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * Send RSAK PDU + */ + (void) sscop_send_rsak(sop); + + /* + * Back to waiting for peer's RSAK + */ + sop->so_state = SOS_OUTRESYN; + + return; +} + diff --git a/sys/netatm/uni/qsaal1_sigcpcs.c b/sys/netatm/uni/qsaal1_sigcpcs.c new file mode 100644 index 0000000..1d62165 --- /dev/null +++ b/sys/netatm/uni/qsaal1_sigcpcs.c @@ -0,0 +1,1545 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: qsaal1_sigcpcs.c,v 1.7 1998/04/07 23:21:03 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * ITU-T Q.SAAL1 - Process CPCS-signals (SSCOP PDUs) + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: qsaal1_sigcpcs.c,v 1.7 1998/04/07 23:21:03 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Local functions + */ +static void sscop_bgn_outconn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_end_outresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_end_conresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_end_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_endak_outresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_rs_outresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_rs_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_rsak_conresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_sd_inresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_sd_conresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_sd_process __P((struct sscop *, KBuffer *, caddr_t, int)); +static void sscop_sd_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_sdp_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_poll_inresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_poll_conresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_poll_ready __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_stat_conresyn __P((struct sscop *, KBuffer *, caddr_t)); +static void sscop_ustat_conresyn __P((struct sscop *, KBuffer *, caddr_t)); + + +/* + * PDU type state lookup tables + */ +/* BGN PDU */ +static void (*sscop_bgn_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_bgn_idle, /* SOS_IDLE */ + sscop_bgn_outconn, /* SOS_OUTCONN */ + sscop_noop, /* SOS_INCONN */ + sscop_bgn_outdisc, /* SOS_OUTDISC */ + sscop_bgn_outresyn, /* SOS_OUTRESYN */ + sscop_bgn_inresyn, /* SOS_INRESYN */ + sscop_bgn_outresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_bgn_inresyn, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* BGAK PDU */ +static void (*sscop_bgak_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_bgak_idle, /* SOS_IDLE */ + sscop_bgak_outconn, /* SOS_OUTCONN */ + sscop_bgak_error, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_bgak_error, /* SOS_OUTRESYN */ + sscop_bgak_error, /* SOS_INRESYN */ + sscop_bgak_error, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_noop, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* BGREJ PDU */ +static void (*sscop_bgrej_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_bgrej_error, /* SOS_IDLE */ + sscop_bgrej_outconn, /* SOS_OUTCONN */ + sscop_bgrej_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_bgrej_outresyn, /* SOS_OUTRESYN */ + sscop_bgrej_ready, /* SOS_INRESYN */ + sscop_bgrej_outresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_bgrej_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* END PDU */ +static void (*sscop_end_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_end_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_end_inconn, /* SOS_INCONN */ + sscop_end_outdisc, /* SOS_OUTDISC */ + sscop_end_outresyn, /* SOS_OUTRESYN */ + sscop_end_ready, /* SOS_INRESYN */ + sscop_end_conresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_end_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* ENDAK PDU */ +static void (*sscop_endak_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_noop, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_endak_inconn, /* SOS_INCONN */ + sscop_endak_outdisc, /* SOS_OUTDISC */ + sscop_endak_outresyn, /* SOS_OUTRESYN */ + sscop_endak_ready, /* SOS_INRESYN */ + sscop_endak_outresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_endak_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* RS PDU */ +static void (*sscop_rs_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_rs_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_rs_error, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_rs_outresyn, /* SOS_OUTRESYN */ + sscop_noop, /* SOS_INRESYN */ + sscop_noop, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_rs_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* RSAK PDU */ +static void (*sscop_rsak_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_rsak_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_rsak_error, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_rsak_outresyn, /* SOS_OUTRESYN */ + sscop_rsak_error, /* SOS_INRESYN */ + sscop_rsak_conresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_rsak_error, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* SD PDU */ +static void (*sscop_sd_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_sd_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_sd_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_sd_ready, /* SOS_OUTRESYN */ + sscop_sd_inresyn, /* SOS_INRESYN */ + sscop_sd_conresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_sd_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* SDP PDU */ +static void (*sscop_sdp_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_sd_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_sd_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_sdp_ready, /* SOS_OUTRESYN */ + sscop_sd_inresyn, /* SOS_INRESYN */ + sscop_sd_conresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_sdp_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* POLL PDU */ +static void (*sscop_poll_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_poll_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_poll_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_poll_ready, /* SOS_OUTRESYN */ + sscop_poll_inresyn, /* SOS_INRESYN */ + sscop_poll_conresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_poll_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* STAT PDU */ +static void (*sscop_stat_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_stat_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_stat_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_noop, /* SOS_OUTRESYN */ + sscop_stat_ready, /* SOS_INRESYN */ + sscop_stat_conresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_stat_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* USTAT PDU */ +static void (*sscop_ustat_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_ustat_idle, /* SOS_IDLE */ + sscop_noop, /* SOS_OUTCONN */ + sscop_ustat_inconn, /* SOS_INCONN */ + sscop_noop, /* SOS_OUTDISC */ + sscop_noop, /* SOS_OUTRESYN */ + sscop_ustat_ready, /* SOS_INRESYN */ + sscop_ustat_conresyn, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_ustat_ready, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* UD PDU */ +static void (*sscop_ud_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_ud_all, /* SOS_IDLE */ + sscop_ud_all, /* SOS_OUTCONN */ + sscop_ud_all, /* SOS_INCONN */ + sscop_ud_all, /* SOS_OUTDISC */ + sscop_ud_all, /* SOS_OUTRESYN */ + sscop_ud_all, /* SOS_INRESYN */ + sscop_ud_all, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_ud_all, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + +/* MD PDU */ +static void (*sscop_md_tab[SOS_NUMSTATES]) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, /* SOS_INST */ + sscop_md_all, /* SOS_IDLE */ + sscop_md_all, /* SOS_OUTCONN */ + sscop_md_all, /* SOS_INCONN */ + sscop_md_all, /* SOS_OUTDISC */ + sscop_md_all, /* SOS_OUTRESYN */ + sscop_md_all, /* SOS_INRESYN */ + sscop_md_all, /* SOS_CONRESYN */ + NULL, /* invalid */ + NULL, /* invalid */ + sscop_md_all, /* SOS_READY */ + sscop_noop /* SOS_TERM */ +}; + + +/* + * PDU type lookup table + */ +void (*(*sscop_qsaal_pdutab[])) + __P((struct sscop *, KBuffer *, caddr_t)) = { + NULL, + sscop_bgn_tab, + sscop_bgak_tab, + sscop_end_tab, + sscop_endak_tab, + sscop_rs_tab, + sscop_rsak_tab, + sscop_bgrej_tab, + sscop_sd_tab, + sscop_sdp_tab, + sscop_poll_tab, + sscop_stat_tab, + sscop_ustat_tab, + sscop_ud_tab, + sscop_md_tab, + NULL +}; + + +/* + * BGN PDU / SOS_OUTCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_bgn_outconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct bgn_pdu *bp = (struct bgn_pdu *)trlr; + int err; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); + + /* + * Notify user of connection establishment + */ + if (sop->so_flags & SOF_REESTAB) { + KB_FREEALL(m); + STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "sscop_bgn_outconn: stack memory\n"); + return; + } + sop->so_flags &= ~SOF_REESTAB; + } else { + STACK_CALL(SSCOP_ESTABLISH_CNF, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "sscop_bgn_outconn: stack memory\n"); + return; + } + } + + /* + * Return an ACK to peer + */ + (void) sscop_send_bgak(sop); + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Reset receiver variables + */ + qsaal1_reset_rcvr(sop); + + /* + * Start polling timer + */ + sscop_set_poll(sop); + + /* + * Start lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * OK, we're ready for data + */ + sop->so_state = SOS_READY; + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; +} + + +/* + * END PDU / SOS_OUTRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_end_outresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct end_pdu *ep = (struct end_pdu *)trlr; + int err, source; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Acknowledge END + */ + (void) sscop_send_endak(sop); + + /* + * Get Source value + */ + if (ep->end_type & PT_SOURCE_SSCOP) + source = SSCOP_SOURCE_SSCOP; + else + source = SSCOP_SOURCE_USER; + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "sscop_end_outresyn: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * END PDU / SOS_CONRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_end_conresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Free up buffers + */ + KB_FREEALL(m); + + /* + * Acknowledge END + */ + (void) sscop_send_endak(sop); + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "sscop_end_conresyn: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * END PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_end_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct end_pdu *ep = (struct end_pdu *)trlr; + int err, source; + + /* + * Stop poll timer + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Stop lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = 0; + + /* + * Acknowledge END + */ + (void) sscop_send_endak(sop); + + /* + * Get Source value + */ + if (ep->end_type & PT_SOURCE_SSCOP) + source = SSCOP_SOURCE_SSCOP; + else + source = SSCOP_SOURCE_USER; + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "sscop_end_ready: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * ENDAK PDU / SOS_OUTRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_endak_outresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Report protocol error + */ + sscop_endak_error(sop, m, trlr); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "sscop_endak_outresyn: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * RS PDU / SOS_OUTRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_rs_outresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Notify user of resynchronization + */ + STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "sscop_rs_outresyn: stack memory\n"); + return; + } + + /* + * Reset receiver state variables + */ + qsaal1_reset_rcvr(sop); + + /* + * Wait for both peer and user responses + */ + sop->so_state = SOS_CONRESYN; + + return; +} + + +/* + * RS PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_rs_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Notify user of resynchronization + */ + STACK_CALL(SSCOP_RESYNC_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "sscop_rs_ready: stack memory\n"); + return; + } + + /* + * Reset receiver state variables + */ + qsaal1_reset_rcvr(sop); + + /* + * Wait for user response + */ + sop->so_state = SOS_INRESYN; + + return; +} + + +/* + * RSAK PDU / SOS_CONRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_rsak_conresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Free buffers + */ + KB_FREEALL(m); + + /* + * Notify user of resynchronization completion + */ + STACK_CALL(SSCOP_RESYNC_CNF, sop->so_upper, sop->so_toku, + sop->so_connvc, 0, 0, err); + if (err) { + sscop_abort(sop, "sscop_rsak_conresyn: stack memory\n"); + return; + } + + /* + * Start the polling timer + */ + sscop_set_poll(sop); + + /* + * Start lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * Continue waiting for user response + */ + sop->so_state = SOS_INRESYN; + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; +} + + +/* + * SD PDU / SOS_INRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_sd_inresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop poll timer + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Stop lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = 0; + + /* + * Record error condition + */ + sscop_sd_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "sscop_sd_inresyn: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Go back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * SD PDU / SOS_CONRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_sd_conresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Record error condition + */ + sscop_sd_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "sscop_sd_conresyn: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Go back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * SD/SDP PDU Common Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU user data buffer chain + * trlr pointer to PDU trailer + * type PDU type (SD or SDP) + * + * Returns: + * none + * + */ +static void +sscop_sd_process(sop, m, trlr, type) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; + int type; +{ + struct sd_pdu *sp; + struct sdp_pdu *spp; + struct poll_pdu poll; + struct pdu_hdr *php; + KBuffer *n; + sscop_seq ns, nps; + int err, space; + + /* + * Get PDU sequence number(s) + */ + if (type == PT_SD) { + sp = (struct sd_pdu *)trlr; + SEQ_SET(ns, ntohl(sp->sd_ns)); + SEQ_SET(nps, 0); + } else { + spp = (struct sdp_pdu *)trlr; + SEQ_SET(ns, ntohl(spp->sdp_ns)); + SEQ_SET(nps, ntohl(spp->sdp_nps)); + } + + /* + * Ensure that the sequence number fits within the window + */ + if (SEQ_GEQ(ns, sop->so_rcvmax, sop->so_rcvnext)) { + KB_FREEALL(m); + return; + } + + /* + * If this is the next in-sequence PDU, hand it to user + */ + if (ns == sop->so_rcvnext) { + STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, ns, err); + if (err) { + KB_FREEALL(m); + return; + } + + /* + * Bump next expected sequence number + */ + SEQ_INCR(sop->so_rcvnext, 1); + + /* + * Slide receive window down + */ + SEQ_INCR(sop->so_rcvmax, 1); + + /* + * Is this the highest sequence PDU we've received?? + */ + if (ns == sop->so_rcvhigh) { + /* + * Yes, bump the limit and exit + */ + sop->so_rcvhigh = sop->so_rcvnext; + if (type == PT_SDP) + goto dopoll; + return; + } + + /* + * This is a retransmitted PDU, so see if we have + * more in-sequence PDUs already queued up + */ + while ((php = sop->so_recv_hd) && + (php->ph_ns == sop->so_rcvnext)) { + + /* + * Yup we do, so remove next PDU from queue and + * pass it up to the user as well + */ + sop->so_recv_hd = php->ph_recv_lk; + if (sop->so_recv_hd == NULL) + sop->so_recv_tl = NULL; + STACK_CALL(SSCOP_DATA_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)php->ph_buf, php->ph_ns, + err); + if (err) { + /* + * Should never happen, but... + */ + KB_FREEALL(php->ph_buf); + sscop_abort(sop, + "sscop_sd_process: stack memory\n"); + return; + } + + /* + * Bump next expected sequence number + */ + SEQ_INCR(sop->so_rcvnext, 1); + + /* + * Slide receive window down + */ + SEQ_INCR(sop->so_rcvmax, 1); + } + + /* + * Finished with data...see if we need to poll + */ + if (type == PT_SDP) + goto dopoll; + return; + } + + /* + * We're gonna have to queue this PDU, so find space + * for the PDU header + */ + KB_HEADROOM(m, space); + + /* + * If there's not enough room in the received buffer, + * allocate & link a new buffer for the header + */ + if (space < sizeof(struct pdu_hdr)) { + + KB_ALLOC(n, sizeof(struct pdu_hdr), KB_F_NOWAIT, KB_T_HEADER); + if (n == NULL) { + KB_FREEALL(m); + return; + } + KB_HEADSET(n, sizeof(struct pdu_hdr)); + KB_LEN(n) = 0; + KB_LINKHEAD(n, m); + m = n; + } + + /* + * Build PDU header + * + * We can at least assume/require that the start of + * the user data is aligned. Also note that we don't + * include this header in the buffer len/offset fields. + */ + KB_DATASTART(m, php, struct pdu_hdr *); + php--; + php->ph_ns = ns; + php->ph_buf = m; + + /* + * Insert PDU into the receive queue + */ + if (sscop_recv_insert(sop, php)) { + /* + * Oops, a duplicate sequence number PDU is already on + * the queue, somethings wrong here. + */ + sscop_maa_error(sop, 'Q'); + + /* + * Free buffers + */ + KB_FREEALL(m); + + /* + * Reestablish a new connection + */ + qsaal1_reestablish(sop); + + return; + } + + /* + * Are we at the high-water mark?? + */ + if (ns == sop->so_rcvhigh) { + /* + * Yes, just bump the mark + */ + SEQ_INCR(sop->so_rcvhigh, 1); + + if (type == PT_SDP) + goto dopoll; + return; + } + + /* + * Are we beyond the high-water mark?? + */ + if (SEQ_GT(ns, sop->so_rcvhigh, sop->so_rcvnext)) { + /* + * Yes, then there's a missing PDU, so inform the transmitter + */ + if (type == PT_SD) + (void) sscop_send_ustat(sop, ns); + + /* + * Update high-water mark + */ + sop->so_rcvhigh = SEQ_ADD(ns, 1); + } + + if (type == PT_SD) + return; + +dopoll: + /* + * Do the "poll" part of an SDP PDU + */ + poll.poll_nps = htonl(nps); + poll.poll_ns = htonl((PT_POLL << PT_TYPE_SHIFT) | ns); + sscop_poll_ready(sop, NULL, (caddr_t)&poll); + return; +} + + +/* + * SD PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_sd_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + /* + * Just call common SD/SDP processor + */ + sscop_sd_process(sop, m, trlr, PT_SD); + + return; +} + + +/* + * SDP PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_sdp_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + /* + * Just call common SD/SDP processor + */ + sscop_sd_process(sop, m, trlr, PT_SDP); + + return; +} + + +/* + * POLL PDU / SOS_INRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_poll_inresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop poll timer + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Stop lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = 0; + + /* + * Report protocol error + */ + sscop_poll_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "sscop_poll_inresyn: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * POLL PDU / SOS_CONRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_poll_conresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Record error condition + */ + sscop_poll_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "sscop_poll_conresyn: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Go back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * POLL PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_poll_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct poll_pdu *pp = (struct poll_pdu *)trlr; + sscop_seq nps; + + NTOHL(pp->poll_ns); + + /* + * If the poll sequence number is less than highest number + * we've already seen, something's wrong - so attempt to + * reestablish a new connection. + */ + if (SEQ_LT(pp->poll_ns, sop->so_rcvhigh, sop->so_rcvnext)) { + /* + * Record error condition + */ + sscop_maa_error(sop, 'Q'); + + /* + * Free buffers + */ + KB_FREEALL(m); + + /* + * Reestablish a new connection + */ + qsaal1_reestablish(sop); + + return; + } + + /* + * Set a new "next highest" sequence number expected + */ + if (SEQ_LT(pp->poll_ns, sop->so_rcvmax, sop->so_rcvnext)) + SEQ_SET(sop->so_rcvhigh, pp->poll_ns); + else + sop->so_rcvhigh = sop->so_rcvmax; + + /* + * Return a STAT PDU to peer + */ + SEQ_SET(nps, ntohl(pp->poll_nps)); + KB_FREEALL(m); + (void) sscop_send_stat(sop, nps); + + return; +} + + +/* + * STAT PDU / SOS_CONRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_stat_conresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Record error condition + */ + sscop_stat_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "sscop_stat_conresyn: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Go back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * USTAT PDU / SOS_CONRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +static void +sscop_ustat_conresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Record error condition + */ + sscop_ustat_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "sscop_ustat_conresyn: stack memory\n"); + return; + } + + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Go back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + diff --git a/sys/netatm/uni/qsaal1_subr.c b/sys/netatm/uni/qsaal1_subr.c new file mode 100644 index 0000000..ed4b43c --- /dev/null +++ b/sys/netatm/uni/qsaal1_subr.c @@ -0,0 +1,206 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: qsaal1_subr.c,v 1.6 1998/04/07 23:21:17 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * ITU-T Q.SAAL1 - Subroutines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: qsaal1_subr.c,v 1.6 1998/04/07 23:21:17 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Re-establish a new SSCOP Connection + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +qsaal1_reestablish(sop) + struct sscop *sop; +{ + + /* + * Stop polling timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Note that we're reestablishing a connection + */ + sop->so_flags |= SOF_REESTAB; + + /* + * Send first BGN PDU + */ + sop->so_connctl = 1; + (void) sscop_send_bgn(sop, SSCOP_SOURCE_SSCOP); + + /* + * Reset transmit variables + */ + qsaal1_reset_xmit(sop); + + /* + * Set retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + /* + * Wait for BGAK + */ + sop->so_state = SOS_OUTCONN; + + return; +} + + +/* + * Reset connection's transmitter state + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +qsaal1_reset_xmit(sop) + struct sscop *sop; +{ + + /* + * Drain the transmission queues + */ + sscop_xmit_drain(sop); + + /* + * Reset transmit variables + */ + SEQ_SET(sop->so_send, 0); + SEQ_SET(sop->so_pollsend, 0); + SEQ_SET(sop->so_ack, 0); + SEQ_SET(sop->so_pollack, 0); + if (sop->so_state != SOS_INCONN) + SEQ_SET(sop->so_sendmax, 0); + sop->so_polldata = 0; + + return; +} + + +/* + * Reset connection's receiver state + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +qsaal1_reset_rcvr(sop) + struct sscop *sop; +{ + + /* + * Drain the receiver queues + */ + sscop_rcvr_drain(sop); + + /* + * Reset transmit variables + */ + SEQ_SET(sop->so_rcvnext, 0); + SEQ_SET(sop->so_rcvhigh, 0); + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + + return; +} + + +/* + * Clear connection's connection data + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +qsaal1_clear_connection(sop) + struct sscop *sop; +{ + + /* + * Can we clear transmit buffers ?? + */ + if ((sop->so_flags & SOF_NOCLRBUF) == 0) { + /* + * Yes, drain the transmission queues + */ + sscop_xmit_drain(sop); + } + + /* + * Clear service required flag + */ + sop->so_flags &= ~SOF_XMITSRVC; + + /* + * Drain receive queue buffers + */ + sscop_rcvr_drain(sop); + + return; +} + diff --git a/sys/netatm/uni/sscf_uni.c b/sys/netatm/uni/sscf_uni.c new file mode 100644 index 0000000..b5fd7fb --- /dev/null +++ b/sys/netatm/uni/sscf_uni.c @@ -0,0 +1,317 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sscf_uni.c,v 1.6 1998/03/24 21:10:38 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * Signalling AAL SSCF at the UNI + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscf_uni.c,v 1.6 1998/03/24 21:10:38 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscf_uni.h> +#include <netatm/uni/sscf_uni_var.h> + + +/* + * Global variables + */ +int sscf_uni_vccnt = 0; + +/* + * Local functions + */ +static int sscf_uni_inst __P((struct stack_defn **, Atm_connvc *)); + +/* + * Local variables + */ +static struct sp_info sscf_uni_pool = { + "sscf uni pool", /* si_name */ + sizeof(struct univcc), /* si_blksiz */ + 5, /* si_blkcnt */ + 100 /* si_maxallow */ +}; + +static struct stack_defn sscf_uni_service = { + NULL, + SAP_SSCF_UNI, + 0, + sscf_uni_inst, + sscf_uni_lower, + sscf_uni_upper, + 0 +}; + +static struct t_atm_cause sscf_uni_cause = { + T_ATM_ITU_CODING, + T_ATM_LOC_USER, + T_ATM_CAUSE_TEMPORARY_FAILURE, + {0, 0, 0, 0} +}; + + +/* + * Initialize SSCF UNI processing + * + * This will be called during module loading. We will register our stack + * service and wait for someone to talk to us. + * + * Arguments: + * none + * + * Returns: + * 0 initialization was successful + * errno initialization failed - reason indicated + * + */ +int +sscf_uni_start() +{ + int err = 0; + + /* + * Register stack service + */ + if (err = atm_stack_register(&sscf_uni_service)) + goto done; + +done: + return (err); +} + + +/* + * Terminate SSCF UNI processing + * + * This will be called just prior to unloading the module from memory. All + * signalling instances should have been terminated by now, so we just free + * up all of our resources. + * + * Called at splnet. + * + * Arguments: + * none + * + * Returns: + * 0 termination was successful + * errno termination failed - reason indicated + * + */ +int +sscf_uni_stop() +{ + /* + * Any connections still exist?? + */ + if (sscf_uni_vccnt) { + + /* + * Yes, can't stop yet + */ + return (EBUSY); + } + + /* + * Deregister the stack service + */ + (void) atm_stack_deregister(&sscf_uni_service); + + /* + * Free our storage pools + */ + atm_release_pool(&sscf_uni_pool); + + return (0); +} + + +/* + * SSCF_UNI Stack Instantiation + * + * Called at splnet. + * + * Arguments: + * ssp pointer to array of stack definition pointers for connection + * ssp[0] points to upper layer's stack service definition + * ssp[1] points to this layer's stack service definition + * ssp[2] points to lower layer's stack service definition + * cvp pointer to connection vcc for this stack + * + * Returns: + * 0 instantiation successful + * errno instantiation failed - reason indicated + * + */ +static int +sscf_uni_inst(ssp, cvp) + struct stack_defn **ssp; + Atm_connvc *cvp; +{ + struct stack_defn *sdp_up = ssp[0], + *sdp_me = ssp[1], + *sdp_low = ssp[2]; + struct univcc *uvp; + int err; + + ATM_DEBUG2("sscf_uni_inst: ssp=0x%x, cvp=0x%x\n", ssp, cvp); + + /* + * Validate lower SAP + */ + if (sdp_low->sd_sap != SAP_SSCOP) + return (EINVAL); + + /* + * Allocate our control block + */ + uvp = (struct univcc *)atm_allocate(&sscf_uni_pool); + if (uvp == NULL) + return (ENOMEM); + + uvp->uv_ustate = UVU_INST; + uvp->uv_lstate = UVL_INST; + uvp->uv_connvc = cvp; + uvp->uv_toku = sdp_up->sd_toku; + uvp->uv_upper = sdp_up->sd_upper; + sscf_uni_vccnt++; + + /* + * Store my token into service definition + */ + sdp_me->sd_toku = uvp; + + /* + * Update and save input buffer headroom + */ + HEADIN(cvp, 0, 0); + /* uvp->uv_headin = cvp->cvc_attr.headin; */ + + /* + * Pass instantiation down the stack + */ + err = sdp_low->sd_inst(ssp + 1, cvp); + if (err) { + /* + * Lower layer instantiation failed, free our resources + */ + atm_free((caddr_t)uvp); + sscf_uni_vccnt--; + return (err); + } + + /* + * Save and update output buffer headroom + */ + /* uvp->uv_headout = cvp->cvc_attr.headout; */ + HEADOUT(cvp, 0, 0); + + /* + * Save lower layer's interface info + */ + uvp->uv_lower = sdp_low->sd_lower; + uvp->uv_tokl = sdp_low->sd_toku; + + return (0); +} + + +/* + * Abort an SSCF_UNI connection + * + * Called when an unrecoverable or "should never happen" error occurs. + * We just log a message and request the signalling manager to abort the + * connection. + * + * Arguments: + * uvp pointer to univcc control block + * msg pointer to error message + * + * Returns: + * none + * + */ +void +sscf_uni_abort(uvp, msg) + struct univcc *uvp; + char *msg; +{ + /* + * Log error message + */ + log(LOG_ERR, msg); + + /* + * Set termination states + */ + uvp->uv_ustate = UVU_TERM; + uvp->uv_lstate = UVL_TERM; + + /* + * Tell Connection Manager to abort this connection + */ + (void) atm_cm_abort(uvp->uv_connvc, &sscf_uni_cause); +} + + +/* + * Print an SSCF PDU + * + * Arguments: + * uvp pointer to univcc control block + * m pointer to pdu buffer chain + * msg pointer to message string + * + * Returns: + * none + * + */ +void +sscf_uni_pdu_print(uvp, m, msg) + struct univcc *uvp; + KBuffer *m; + char *msg; +{ + char buf[128]; + struct vccb *vcp; + + vcp = uvp->uv_connvc->cvc_vcc; + sprintf(buf, "sscf_uni %s: vcc=(%d,%d)\n", + msg, vcp->vc_vpi, vcp->vc_vci); + atm_pdu_print(m, buf); +} + diff --git a/sys/netatm/uni/sscf_uni.h b/sys/netatm/uni/sscf_uni.h new file mode 100644 index 0000000..cf24446 --- /dev/null +++ b/sys/netatm/uni/sscf_uni.h @@ -0,0 +1,47 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sscf_uni.h,v 1.2 1997/05/06 22:19:34 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCF UNI protocol definitions + * + */ + +#ifndef _UNI_SSCF_UNI_H +#define _UNI_SSCF_UNI_H + +/* + * SSCF_UNI API definitions + */ +#define SSCF_UNI_ESTIND_YES 1 /* Allow new ESTABLISH_IND */ +#define SSCF_UNI_ESTIND_NO 2 /* Disallow new ESTABLISH_IND */ + +#endif /* _UNI_SSCF_UNI_H */ diff --git a/sys/netatm/uni/sscf_uni_lower.c b/sys/netatm/uni/sscf_uni_lower.c new file mode 100644 index 0000000..fe2d839 --- /dev/null +++ b/sys/netatm/uni/sscf_uni_lower.c @@ -0,0 +1,379 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sscf_uni_lower.c,v 1.6 1998/04/07 23:23:26 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCF UNI - SSCF_UNI SAP interface processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscf_uni_lower.c,v 1.6 1998/04/07 23:23:26 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscf_uni.h> +#include <netatm/uni/sscf_uni_var.h> + + +/* + * Local variables + */ +static struct sscop_parms sscf_uni_sscop_parms = { + 4096, /* sp_maxinfo */ + 4096, /* sp_maxuu */ + 4, /* sp_maxcc */ + 25, /* sp_maxpd */ + 1 * ATM_HZ, /* sp_timecc */ + 2 * ATM_HZ, /* sp_timekeep */ + 7 * ATM_HZ, /* sp_timeresp */ + 1 * ATM_HZ, /* sp_timepoll */ + 15 * ATM_HZ, /* sp_timeidle */ + 80 /* sp_rcvwin */ +}; + + +/* + * SSCF_UNI Lower Stack Command Handler + * + * This function will receive all of the stack commands issued from the + * layer above SSCF UNI (ie. Q.2931). + * + * Arguments: + * cmd stack command code + * tok session token + * arg1 command specific argument + * arg2 command specific argument + * + * Returns: + * none + * + */ +void +sscf_uni_lower(cmd, tok, arg1, arg2) + int cmd; + void *tok; + int arg1; + int arg2; +{ + struct univcc *uvp = (struct univcc *)tok; + Atm_connvc *cvp = uvp->uv_connvc; + enum sscop_vers vers; + int err; + + ATM_DEBUG5("sscf_uni_lower: cmd=0x%x, uvp=0x%x, ustate=%d, arg1=0x%x, arg2=0x%x\n", + cmd, (int)uvp, uvp->uv_ustate, arg1, arg2); + + switch (cmd) { + + case SSCF_UNI_INIT: + /* + * Validate state + */ + if (uvp->uv_ustate != UVU_INST) { + log(LOG_ERR, "sscf_uni_lower: SSCF_INIT in ustate=%d\n", + uvp->uv_ustate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + break; + } + + /* + * Validate UNI version + */ + if ((enum uni_vers)arg1 == UNI_VERS_3_0) + vers = SSCOP_VERS_QSAAL; + else if ((enum uni_vers)arg1 == UNI_VERS_3_1) + vers = SSCOP_VERS_Q2110; + else { + sscf_uni_abort(uvp, "sscf_uni: bad version\n"); + break; + } + uvp->uv_vers = (enum uni_vers)arg1; + + /* + * Make ourselves ready and pass on the INIT + */ + uvp->uv_ustate = UVU_RELEASED; + uvp->uv_lstate = UVL_IDLE; + + STACK_CALL(SSCOP_INIT, uvp->uv_lower, uvp->uv_tokl, cvp, + (int)vers, (int)&sscf_uni_sscop_parms, err); + if (err) { + /* + * Should never happen + */ + sscf_uni_abort(uvp, "sscf_uni: INIT failure\n"); + } + break; + + case SSCF_UNI_TERM: + /* + * Set termination states + */ + uvp->uv_ustate = UVU_TERM; + uvp->uv_lstate = UVL_TERM; + + /* + * Pass the TERM down the stack + */ + STACK_CALL(SSCOP_TERM, uvp->uv_lower, uvp->uv_tokl, cvp, + 0, 0, err); + if (err) { + /* + * Should never happen + */ + sscf_uni_abort(uvp, "sscf_uni: TERM failure\n"); + return; + } + atm_free((caddr_t)uvp); + sscf_uni_vccnt--; + break; + + case SSCF_UNI_ESTABLISH_REQ: + /* + * Validation based on user state + */ + switch (uvp->uv_ustate) { + + case UVU_RELEASED: + case UVU_PRELEASE: + /* + * Establishing a new connection + */ + uvp->uv_ustate = UVU_PACTIVE; + uvp->uv_lstate = UVL_OUTCONN; + STACK_CALL(SSCOP_ESTABLISH_REQ, uvp->uv_lower, + uvp->uv_tokl, cvp, + SSCOP_UU_NULL, SSCOP_BR_YES, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVU_ACTIVE: + /* + * Resynchronizing a connection + */ + uvp->uv_ustate = UVU_PACTIVE; + if (uvp->uv_vers == UNI_VERS_3_0) { + uvp->uv_lstate = UVL_OUTCONN; + STACK_CALL(SSCOP_ESTABLISH_REQ, uvp->uv_lower, + uvp->uv_tokl, cvp, + SSCOP_UU_NULL, SSCOP_BR_YES, err); + } else { + uvp->uv_lstate = UVL_OUTRESYN; + STACK_CALL(SSCOP_RESYNC_REQ, uvp->uv_lower, + uvp->uv_tokl, cvp, + SSCOP_UU_NULL, 0, err); + } + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVU_TERM: + /* Ignore */ + break; + + case UVU_INST: + case UVU_PACTIVE: + default: + log(LOG_ERR, "sscf_uni_lower: cmd=0x%x, ustate=%d\n", + cmd, uvp->uv_ustate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCF_UNI_RELEASE_REQ: + /* + * Validate re-establishment parameter + */ + switch (arg1) { + + case SSCF_UNI_ESTIND_YES: + uvp->uv_flags &= ~UVF_NOESTIND; + break; + + case SSCF_UNI_ESTIND_NO: + uvp->uv_flags |= UVF_NOESTIND; + break; + + default: + sscf_uni_abort(uvp, "sscf_uni: bad estind value\n"); + return; + } + + /* + * Validation based on user state + */ + switch (uvp->uv_ustate) { + + case UVU_RELEASED: + /* + * Releasing a non-existant connection + */ + STACK_CALL(SSCF_UNI_RELEASE_CNF, uvp->uv_upper, + uvp->uv_toku, cvp, + 0, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVU_PACTIVE: + case UVU_ACTIVE: + /* + * Releasing a connection + */ + uvp->uv_ustate = UVU_PRELEASE; + uvp->uv_lstate = UVL_OUTDISC; + STACK_CALL(SSCOP_RELEASE_REQ, uvp->uv_lower, + uvp->uv_tokl, cvp, + SSCOP_UU_NULL, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVU_TERM: + /* Ignore */ + break; + + case UVU_INST: + case UVU_PRELEASE: + default: + log(LOG_ERR, "sscf_uni_lower: cmd=0x%x, ustate=%d\n", + cmd, uvp->uv_ustate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCF_UNI_DATA_REQ: +#ifdef notdef + sscf_uni_pdu_print(uvp, (KBuffer *)arg1, "DATA_REQ"); +#endif + + /* + * Validation based on user state + */ + switch (uvp->uv_ustate) { + + case UVU_ACTIVE: + /* + * Send assured data on connection + */ + STACK_CALL(SSCOP_DATA_REQ, uvp->uv_lower, + uvp->uv_tokl, cvp, + arg1, 0, err); + if (err) { + KB_FREEALL((KBuffer *)arg1); + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVU_RELEASED: + case UVU_TERM: + /* + * Release supplied buffers and ignore + */ + KB_FREEALL((KBuffer *)arg1); + break; + + case UVU_INST: + case UVU_PACTIVE: + case UVU_PRELEASE: + default: + KB_FREEALL((KBuffer *)arg1); + log(LOG_ERR, "sscf_uni_lower: cmd=0x%x, ustate=%d\n", + cmd, uvp->uv_ustate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCF_UNI_UNITDATA_REQ: +#ifdef notdef + sscf_uni_pdu_print(uvp, (KBuffer *)arg1, "UNITDATA_REQ"); +#endif + + /* + * Validation based on user state + */ + switch (uvp->uv_ustate) { + + case UVU_RELEASED: + case UVU_PACTIVE: + case UVU_PRELEASE: + case UVU_ACTIVE: + /* + * Send unassured data on connection + */ + STACK_CALL(SSCOP_UNITDATA_REQ, uvp->uv_lower, + uvp->uv_tokl, cvp, + arg1, 0, err); + if (err) { + KB_FREEALL((KBuffer *)arg1); + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVU_TERM: + /* + * Release supplied buffers and ignore + */ + KB_FREEALL((KBuffer *)arg1); + break; + + case UVU_INST: + default: + KB_FREEALL((KBuffer *)arg1); + log(LOG_ERR, "sscf_uni_lower: cmd=0x%x, ustate=%d\n", + cmd, uvp->uv_ustate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + default: + log(LOG_ERR, "sscf_uni_lower: unknown cmd 0x%x, uvp=0x%x\n", + cmd, (int)uvp); + } + + return; +} + diff --git a/sys/netatm/uni/sscf_uni_upper.c b/sys/netatm/uni/sscf_uni_upper.c new file mode 100644 index 0000000..2febb5c --- /dev/null +++ b/sys/netatm/uni/sscf_uni_upper.c @@ -0,0 +1,625 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sscf_uni_upper.c,v 1.7 1998/06/29 22:15:31 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCF UNI - SSCOP SAP interface processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscf_uni_upper.c,v 1.7 1998/06/29 22:15:31 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscf_uni.h> +#include <netatm/uni/sscf_uni_var.h> + + +/* + * SSCF_UNI Upper Stack Command Handler + * + * This function will receive all of the stack commands issued from the + * layer below SSCF UNI (ie. SSCOP). + * + * Arguments: + * cmd stack command code + * tok session token + * arg1 command specific argument + * arg2 command specific argument + * + * Returns: + * none + * + */ +void +sscf_uni_upper(cmd, tok, arg1, arg2) + int cmd; + void *tok; + int arg1; + int arg2; +{ + struct univcc *uvp = (struct univcc *)tok; + Atm_connvc *cvp = uvp->uv_connvc; + int err; + + ATM_DEBUG5("sscf_uni_upper: cmd=0x%x, uvp=0x%x, lstate=%d, arg1=0x%x, arg2=0x%x\n", + cmd, (int)uvp, uvp->uv_lstate, arg1, arg2); + + switch (cmd) { + + case SSCOP_ESTABLISH_IND: + /* + * We don't support SSCOP User-to-User data, so just + * get rid of any supplied to us + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * Validation based on sscop state + */ + switch (uvp->uv_lstate) { + + case UVL_READY: + if (uvp->uv_vers != UNI_VERS_3_0) { + goto seqerr; + } + goto doestind; + + case UVL_IDLE: + /* + * Incoming connection establishment request + */ + + /* + * If user doesn't want any more incoming sessions + * accepted, then refuse request + */ + if (uvp->uv_flags & UVF_NOESTIND) { + STACK_CALL(SSCOP_RELEASE_REQ, uvp->uv_lower, + uvp->uv_tokl, cvp, + SSCOP_UU_NULL, 0, err); + if (err) { + sscf_uni_abort(uvp, + "sscf_uni: stack memory\n"); + return; + } + break; + } + +doestind: + /* + * Tell sscop we've accepted the new connection + */ + uvp->uv_lstate = UVL_READY; + STACK_CALL(SSCOP_ESTABLISH_RSP, uvp->uv_lower, + uvp->uv_tokl, cvp, + SSCOP_UU_NULL, SSCOP_BR_YES, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + + /* + * Now notify the user of the new connection + */ + uvp->uv_ustate = UVU_ACTIVE; + STACK_CALL(SSCF_UNI_ESTABLISH_IND, uvp->uv_upper, + uvp->uv_toku, cvp, + SSCOP_UU_NULL, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVL_TERM: + /* + * Ignoring everything + */ + break; + + case UVL_INST: + case UVL_OUTCONN: + case UVL_INCONN: + case UVL_OUTDISC: + case UVL_OUTRESYN: + case UVL_INRESYN: + case UVL_RECOVERY: + default: +seqerr: + log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n", + cmd, uvp->uv_lstate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCOP_ESTABLISH_CNF: + /* + * We don't support SSCOP User-to-User data, so just + * get rid of any supplied to us + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * Validation based on sscop state + */ + switch (uvp->uv_lstate) { + + case UVL_OUTCONN: + /* + * Outgoing connection establishment completed + */ + + /* + * Tell the user that the connection is established + */ + uvp->uv_ustate = UVU_ACTIVE; + uvp->uv_lstate = UVL_READY; + STACK_CALL(SSCF_UNI_ESTABLISH_CNF, uvp->uv_upper, + uvp->uv_toku, cvp, + SSCOP_UU_NULL, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVL_TERM: + /* + * Ignoring everything + */ + break; + + case UVL_INST: + case UVL_IDLE: + case UVL_INCONN: + case UVL_OUTDISC: + case UVL_OUTRESYN: + case UVL_INRESYN: + case UVL_RECOVERY: + case UVL_READY: + default: + log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n", + cmd, uvp->uv_lstate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCOP_RELEASE_IND: + /* + * We don't support SSCOP User-to-User data, so just + * get rid of any supplied to us + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * Validation based on sscop state + */ + switch (uvp->uv_lstate) { + + case UVL_OUTCONN: + case UVL_OUTRESYN: + case UVL_READY: + /* + * Peer requesting connection termination + */ + + /* + * Notify the user that the connection + * has been terminated + */ + uvp->uv_ustate = UVU_RELEASED; + uvp->uv_lstate = UVL_IDLE; + STACK_CALL(SSCF_UNI_RELEASE_IND, uvp->uv_upper, + uvp->uv_toku, cvp, + SSCOP_UU_NULL, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVL_TERM: + /* + * Ignoring everything + */ + break; + + case UVL_INST: + case UVL_IDLE: + case UVL_INCONN: + case UVL_OUTDISC: + case UVL_INRESYN: + case UVL_RECOVERY: + default: + log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n", + cmd, uvp->uv_lstate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCOP_RELEASE_CNF: + /* + * Validation based on sscop state + */ + switch (uvp->uv_lstate) { + + case UVL_OUTDISC: + /* + * Peer acknowledging connection termination + */ + + /* + * Notify the user that the connection + * termination is completed + */ + uvp->uv_ustate = UVU_RELEASED; + uvp->uv_lstate = UVL_IDLE; + STACK_CALL(SSCF_UNI_RELEASE_CNF, uvp->uv_upper, + uvp->uv_toku, cvp, + SSCOP_UU_NULL, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVL_TERM: + /* + * Ignoring everything + */ + break; + + case UVL_INST: + case UVL_IDLE: + case UVL_OUTCONN: + case UVL_INCONN: + case UVL_OUTRESYN: + case UVL_INRESYN: + case UVL_RECOVERY: + case UVL_READY: + default: + log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n", + cmd, uvp->uv_lstate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCOP_DATA_IND: +#ifdef notdef + sscf_uni_pdu_print(uvp, (KBuffer *)arg1, "DATA_IND"); +#endif + + /* + * Validation based on sscop state + */ + switch (uvp->uv_lstate) { + + case UVL_READY: + /* + * Incoming assured data from peer + */ + + /* + * Pass the data up to the user + */ + STACK_CALL(SSCF_UNI_DATA_IND, uvp->uv_upper, + uvp->uv_toku, cvp, + arg1, 0, err); + if (err) { + KB_FREEALL((KBuffer *)arg1); + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVL_TERM: + /* + * Ignoring everything + */ + KB_FREEALL((KBuffer *)arg1); + break; + + case UVL_INST: + case UVL_IDLE: + case UVL_OUTCONN: + case UVL_INCONN: + case UVL_OUTDISC: + case UVL_OUTRESYN: + case UVL_INRESYN: + case UVL_RECOVERY: + default: + KB_FREEALL((KBuffer *)arg1); + log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n", + cmd, uvp->uv_lstate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCOP_RESYNC_IND: + /* + * We don't support SSCOP User-to-User data, so just + * get rid of any supplied to us + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * Validation based on sscop state + */ + switch (uvp->uv_lstate) { + + case UVL_READY: + /* + * Incoming connection resynchronization request + */ + + /* + * Send resynch acknowledgement to sscop + */ + STACK_CALL(SSCOP_RESYNC_RSP, uvp->uv_lower, + uvp->uv_tokl, cvp, + 0, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + + if (uvp->uv_vers != UNI_VERS_3_0) { + + /* + * Notify the user that the connection + * has been resynced + */ + STACK_CALL(SSCF_UNI_ESTABLISH_IND, + uvp->uv_upper, uvp->uv_toku, cvp, + SSCOP_UU_NULL, 0, err); + if (err) { + sscf_uni_abort(uvp, + "sscf_uni: stack memory\n"); + return; + } + } + break; + + case UVL_TERM: + /* + * Ignoring everything + */ + break; + + case UVL_INST: + case UVL_IDLE: + case UVL_OUTCONN: + case UVL_INCONN: + case UVL_OUTDISC: + case UVL_OUTRESYN: + case UVL_INRESYN: + case UVL_RECOVERY: + default: + log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n", + cmd, uvp->uv_lstate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCOP_RESYNC_CNF: + /* + * Not supported in version 3.0 + */ + if (uvp->uv_vers == UNI_VERS_3_0) { + sscf_uni_abort(uvp, + "sscf_uni: SSCOP_RESYNC_CNF in 3.0\n"); + return; + } + + /* + * Validation based on sscop state + */ + switch (uvp->uv_lstate) { + + case UVL_OUTRESYN: + /* + * Peer acknowledging connection resynchronization + */ + + /* + * Now notify the user that the connection + * has been resynced + */ + uvp->uv_ustate = UVU_ACTIVE; + uvp->uv_lstate = UVL_READY; + STACK_CALL(SSCF_UNI_ESTABLISH_CNF, uvp->uv_upper, + uvp->uv_toku, cvp, + SSCOP_UU_NULL, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVL_TERM: + /* + * Ignoring everything + */ + break; + + case UVL_INST: + case UVL_IDLE: + case UVL_OUTCONN: + case UVL_INCONN: + case UVL_OUTDISC: + case UVL_INRESYN: + case UVL_RECOVERY: + case UVL_READY: + default: + log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n", + cmd, uvp->uv_lstate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCOP_RECOVER_IND: + /* + * Not supported in version 3.0 + */ + if (uvp->uv_vers == UNI_VERS_3_0) { + sscf_uni_abort(uvp, + "sscf_uni: SSCOP_RECOVER_IND in 3.0\n"); + return; + } + + /* + * Validation based on sscop state + */ + switch (uvp->uv_lstate) { + + case UVL_READY: + /* + * Recover connection due to internal problems + */ + + /* + * Send recovery acknowledgement to sscop + */ + STACK_CALL(SSCOP_RECOVER_RSP, uvp->uv_lower, + uvp->uv_tokl, cvp, + 0, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + + /* + * Now notify the user that the connection + * has been recovered + */ + STACK_CALL(SSCF_UNI_ESTABLISH_IND, uvp->uv_upper, + uvp->uv_toku, cvp, + SSCOP_UU_NULL, 0, err); + if (err) { + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVL_TERM: + /* + * Ignoring everything + */ + break; + + case UVL_INST: + case UVL_IDLE: + case UVL_OUTCONN: + case UVL_INCONN: + case UVL_OUTDISC: + case UVL_OUTRESYN: + case UVL_INRESYN: + case UVL_RECOVERY: + default: + log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n", + cmd, uvp->uv_lstate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCOP_UNITDATA_IND: +#ifdef notdef + sscf_uni_pdu_print(uvp, (KBuffer *)arg1, "UNITDATA_IND"); +#endif + + /* + * Validation based on sscop state + */ + switch (uvp->uv_lstate) { + + case UVL_IDLE: + case UVL_OUTCONN: + case UVL_INCONN: + case UVL_OUTDISC: + case UVL_OUTRESYN: + case UVL_INRESYN: + case UVL_RECOVERY: + case UVL_READY: + /* + * Incoming unassured data from peer + */ + + /* + * Pass the data up to the user + */ + STACK_CALL(SSCF_UNI_UNITDATA_IND, uvp->uv_upper, + uvp->uv_toku, cvp, + arg1, 0, err); + if (err) { + KB_FREEALL((KBuffer *)arg1); + sscf_uni_abort(uvp, "sscf_uni: stack memory\n"); + return; + } + break; + + case UVL_TERM: + /* + * Ignoring everything + */ + KB_FREEALL((KBuffer *)arg1); + break; + + case UVL_INST: + default: + KB_FREEALL((KBuffer *)arg1); + log(LOG_ERR, "sscf_uni_upper: cmd=0x%x, lstate=%d\n", + cmd, uvp->uv_lstate); + sscf_uni_abort(uvp, "sscf_uni: sequence err\n"); + } + break; + + case SSCOP_RETRIEVE_IND: + case SSCOP_RETRIEVECMP_IND: + /* + * Not supported + */ + default: + log(LOG_ERR, "sscf_uni_upper: unknown cmd 0x%x, uvp=0x%x\n", + cmd, (int)uvp); + } + + return; +} + diff --git a/sys/netatm/uni/sscf_uni_var.h b/sys/netatm/uni/sscf_uni_var.h new file mode 100644 index 0000000..ffed7de --- /dev/null +++ b/sys/netatm/uni/sscf_uni_var.h @@ -0,0 +1,115 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sscf_uni_var.h,v 1.5 1998/02/19 20:22:05 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCF UNI protocol control blocks + * + */ + +#ifndef _UNI_SSCF_UNI_VAR_H +#define _UNI_SSCF_UNI_VAR_H + +/* + * Structure containing information for each SSCF UNI connection. + */ +struct univcc { + u_char uv_ustate; /* SSCF-User state (see below) */ + u_char uv_lstate; /* SSCF-SSCOP state (see below) */ + u_short uv_flags; /* Connection flags (see below) */ + enum uni_vers uv_vers; /* UNI version */ + + /* Stack variables */ + Atm_connvc *uv_connvc; /* Connection vcc for this stack */ + void *uv_toku; /* Stack upper layer's token */ + void *uv_tokl; /* Stack lower layer's token */ + void (*uv_upper) /* Stack upper layer's interface */ + __P((int, void *, int, int)); + void (*uv_lower) /* Stack lower layer's interface */ + __P((int, void *, int, int)); +}; + +/* + * SSCF to SAAL User (Q.2931) Interface States + */ +#define UVU_INST 0 /* Instantiated, waiting for INIT */ +#define UVU_RELEASED 1 /* Connection released */ +#define UVU_PACTIVE 2 /* Awaiting connection establishment */ +#define UVU_PRELEASE 3 /* Awaiting connection release */ +#define UVU_ACTIVE 4 /* Connection established */ +#define UVU_TERM 5 /* Waiting for TERM */ + +/* + * SSCF to SSCOP Interface States + */ +#define UVL_INST 0 /* Instantiated, waiting for INIT */ +#define UVL_IDLE 1 /* Idle */ +#define UVL_OUTCONN 2 /* Outgoing connection pending */ +#define UVL_INCONN 3 /* Incoming connection pending */ +#define UVL_OUTDISC 4 /* Outgoing disconnection pending */ +#define UVL_OUTRESYN 5 /* Outgoing resynchronization pending */ +#define UVL_INRESYN 6 /* Incoming resynchornization pending */ +#define UVL_RECOVERY 8 /* Recovery pending */ +#define UVL_READY 10 /* Data transfer ready */ +#define UVL_TERM 11 /* Waiting for TERM */ + +/* + * Connection Flags + */ +#define UVF_NOESTIND 0x0001 /* Don't process ESTABLISH_IND */ + + +#ifdef ATM_KERNEL +/* + * Global function declarations + */ + /* sscf_uni.c */ +int sscf_uni_start __P((void)); +int sscf_uni_stop __P((void)); +void sscf_uni_abort __P((struct univcc *, char *)); +void sscf_uni_pdu_print __P((struct univcc *, KBuffer *, + char *)); + + /* sscf_uni_lower.c */ +void sscf_uni_lower __P((int, void *, int, int)); + + /* sscf_uni_upper.c */ +void sscf_uni_upper __P((int, void *, int, int)); + + +/* + * External variables + */ +extern int sscf_uni_vccnt; + +#endif /* ATM_KERNEL */ + +#endif /* _UNI_SSCF_UNI_VAR_H */ diff --git a/sys/netatm/uni/sscop.c b/sys/netatm/uni/sscop.c new file mode 100644 index 0000000..d65118b --- /dev/null +++ b/sys/netatm/uni/sscop.c @@ -0,0 +1,409 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sscop.c,v 1.6 1998/03/24 21:10:43 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * Service Specific Connection Oriented Protocol (SSCOP) + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscop.c,v 1.6 1998/03/24 21:10:43 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Global variables + */ +int sscop_vccnt = 0; + +struct sscop *sscop_head = NULL; + +struct sscop_stat sscop_stat = {0}; + +struct atm_time sscop_timer = {0, 0}; + +struct sp_info sscop_pool = { + "sscop pool", /* si_name */ + sizeof(struct sscop), /* si_blksiz */ + 5, /* si_blkcnt */ + 100 /* si_maxallow */ +}; + + +/* + * Local functions + */ +static int sscop_inst __P((struct stack_defn **, Atm_connvc *)); + + +/* + * Local variables + */ +static struct stack_defn sscop_service = { + NULL, + SAP_SSCOP, + 0, + sscop_inst, + sscop_lower, + sscop_upper, + 0 +}; + +static struct t_atm_cause sscop_cause = { + T_ATM_ITU_CODING, + T_ATM_LOC_USER, + T_ATM_CAUSE_TEMPORARY_FAILURE, + {0, 0, 0, 0} +}; + +static u_char sscop_maa_log[MAA_ERROR_COUNT] = { + 1, /* A */ + 1, /* B */ + 1, /* C */ + 1, /* D */ + 1, /* E */ + 1, /* F */ + 1, /* G */ + 1, /* H */ + 1, /* I */ + 1, /* J */ + 1, /* K */ + 1, /* L */ + 1, /* M */ + 0, /* N */ + 0, /* O */ + 0, /* P */ + 1, /* Q */ + 1, /* R */ + 1, /* S */ + 1, /* T */ + 1, /* U */ + 0, /* V */ + 0, /* W */ + 0, /* X */ + 1 /* INVAL */ +}; + + +/* + * Initialize SSCOP processing + * + * This will be called during module loading. We will register our stack + * service and wait for someone to talk to us. + * + * Arguments: + * none + * + * Returns: + * 0 initialization was successful + * errno initialization failed - reason indicated + * + */ +int +sscop_start() +{ + int err = 0; + + /* + * Register stack service + */ + if (err = atm_stack_register(&sscop_service)) + goto done; + + /* + * Start up timer + */ + atm_timeout(&sscop_timer, ATM_HZ/SSCOP_HZ, sscop_timeout); + +done: + return (err); +} + + +/* + * Terminate SSCOP processing + * + * This will be called just prior to unloading the module from memory. All + * signalling instances should have been terminated by now, so we just free + * up all of our resources. + * + * Called at splnet. + * + * Arguments: + * none + * + * Returns: + * 0 termination was successful + * errno termination failed - reason indicated + * + */ +int +sscop_stop() +{ + int err = 0; + + /* + * Any connections still exist?? + */ + if (sscop_vccnt) { + + /* + * Yes, can't stop yet + */ + return (EBUSY); + } + + /* + * Stop our timer + */ + (void) atm_untimeout(&sscop_timer); + + /* + * Deregister the stack service + */ + (void) atm_stack_deregister(&sscop_service); + + /* + * Free our storage pools + */ + atm_release_pool(&sscop_pool); + +done: + return (err); +} + + +/* + * SSCOP Stack Instantiation + * + * Called at splnet. + * + * Arguments: + * ssp pointer to array of stack definition pointers for connection + * ssp[0] points to upper layer's stack service definition + * ssp[1] points to this layer's stack service definition + * ssp[2] points to lower layer's stack service definition + * cvp pointer to connection vcc for this stack + * + * Returns: + * 0 instantiation successful + * errno instantiation failed - reason indicated + * + */ +static int +sscop_inst(ssp, cvp) + struct stack_defn **ssp; + Atm_connvc *cvp; +{ + struct stack_defn *sdp_up = ssp[0], + *sdp_me = ssp[1], + *sdp_low = ssp[2]; + struct sscop *sop; + int err; + + ATM_DEBUG2("sscop_inst: ssp=0x%x, cvp=0x%x\n", ssp, cvp); + + /* + * Validate lower SAP + */ + if ((sdp_low->sd_sap & SAP_CLASS_MASK) != SAP_CPCS) + return (EINVAL); + + /* + * Allocate our control block + */ + sop = (struct sscop *)atm_allocate(&sscop_pool); + if (sop == NULL) + return (ENOMEM); + + sop->so_state = SOS_INST; + sop->so_connvc = cvp; + sop->so_toku = sdp_up->sd_toku; + sop->so_upper = sdp_up->sd_upper; + + /* + * Store my token into service definition + */ + sdp_me->sd_toku = sop; + + /* + * Update and save input buffer headroom + */ + HEADIN(cvp, sizeof(struct pdu_hdr), 0); + /* sop->so_headin = cvp->cvc_attr.headin; */ + + /* + * Pass instantiation down the stack + */ + err = sdp_low->sd_inst(ssp + 1, cvp); + if (err) { + /* + * Lower layer instantiation failed, free our resources + */ + atm_free((caddr_t)sop); + return (err); + } + + /* + * Link in connection block + */ + LINK2TAIL(sop, struct sscop, sscop_head, so_next); + sscop_vccnt++; + sscop_stat.sos_connects++; + + /* + * Save and update output buffer headroom + */ + sop->so_headout = cvp->cvc_attr.headout; + HEADOUT(cvp, sizeof(struct pdu_hdr), 0); + + /* + * Save lower layer's interface info + */ + sop->so_lower = sdp_low->sd_lower; + sop->so_tokl = sdp_low->sd_toku; + + /* + * Initialize version (until INIT received) + */ + sop->so_vers = SSCOP_VERS_Q2110; + + return (0); +} + + +/* + * Report Management Error + * + * Called to report an error to the layer management entity. + * + * Arguments: + * sop pointer to sscop control block + * code error code + * + * Returns: + * none + * + */ +void +sscop_maa_error(sop, code) + struct sscop *sop; + int code; +{ + int i; + + /* + * Validate error code + */ + if ((code < MAA_ERROR_MIN) || + (code > MAA_ERROR_MAX)) + code = MAA_ERROR_INVAL; + i = code - MAA_ERROR_MIN; + + /* + * Bump statistics counters + */ + sscop_stat.sos_maa_error[i]++; + + /* + * Log error message + */ + if (sscop_maa_log[i] != 0) { + struct vccb *vcp = sop->so_connvc->cvc_vcc; + struct atm_pif *pip = vcp->vc_pif; + + log(LOG_ERR, + "sscop_maa_error: intf=%s%d vpi=%d vci=%d code=%c state=%d\n", + pip->pif_name, pip->pif_unit, + vcp->vc_vpi, vcp->vc_vci, code, sop->so_state); + } +} + + +/* + * Abort an SSCOP connection + * + * Called when an unrecoverable or "should never happen" error occurs. + * We log a message, send an END PDU to our peer and request the signalling + * manager to abort the connection. + * + * Arguments: + * sop pointer to sscop control block + * msg pointer to error message + * + * Returns: + * none + * + */ +void +sscop_abort(sop, msg) + struct sscop *sop; + char *msg; +{ + Atm_connvc *cvp = sop->so_connvc; + + /* + * Log and count error + */ + log(LOG_ERR, msg); + sscop_stat.sos_aborts++; + + /* + * Send an END PDU as a courtesy to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Set termination state + */ + sop->so_state = SOS_TERM; + + /* + * Flush all of our queues + */ + sscop_xmit_drain(sop); + sscop_rcvr_drain(sop); + + /* + * Tell Connection Manager to abort this connection + */ + (void) atm_cm_abort(cvp, &sscop_cause); +} + diff --git a/sys/netatm/uni/sscop.h b/sys/netatm/uni/sscop.h new file mode 100644 index 0000000..2f786b3 --- /dev/null +++ b/sys/netatm/uni/sscop.h @@ -0,0 +1,80 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sscop.h,v 1.4 1998/08/26 23:29:19 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP protocol definitions + * + */ + +#ifndef _UNI_SSCOP_H +#define _UNI_SSCOP_H + +/* + * SSCOP Version + */ +enum sscop_vers { + SSCOP_VERS_QSAAL, /* Version = Q.SAAL1 */ + SSCOP_VERS_Q2110 /* Version = Q.2110 */ +}; + + +/* + * SSCOP API definitions + */ +#define SSCOP_UU_NULL 0 /* User-to-User Info = null */ +#define SSCOP_RN_TOTAL -1 /* Retrieval Number = Total */ +#define SSCOP_RN_UNKNOWN -2 /* Retrieval Number = Unknown */ +#define SSCOP_BR_YES 1 /* Buffer Release = Yes */ +#define SSCOP_BR_NO 2 /* Buffer Release = No */ +#define SSCOP_SOURCE_SSCOP 1 /* Source = SSCOP */ +#define SSCOP_SOURCE_USER 2 /* Source = User */ +#define SSCOP_SOURCE_LAST 3 /* Source = from last END */ + + +/* + * Connection parameters for an SSCOP entity. + * Passed via an SSCOP_INIT stack call argument. + */ +struct sscop_parms { + u_short sp_maxinfo; /* k - max information field size */ + u_short sp_maxuu; /* j - max SSCOP-UU field size */ + short sp_maxcc; /* MaxCC - max value of VT(CC) */ + short sp_maxpd; /* MaxPD - max value of VT(PD) */ + u_short sp_timecc; /* Timer_CC value (ticks) */ + u_short sp_timekeep; /* Timer_KEEPALIVE value (ticks) */ + u_short sp_timeresp; /* Timer_NO-RESPONSE value (ticks) */ + u_short sp_timepoll; /* Timer_POLL value (ticks) */ + u_short sp_timeidle; /* Timer_IDLE value (ticks) */ + short sp_rcvwin; /* Receiver window size */ +}; + +#endif /* _UNI_SSCOP_H */ diff --git a/sys/netatm/uni/sscop_lower.c b/sys/netatm/uni/sscop_lower.c new file mode 100644 index 0000000..f76f702 --- /dev/null +++ b/sys/netatm/uni/sscop_lower.c @@ -0,0 +1,349 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sscop_lower.c,v 1.6 1998/04/07 23:21:28 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP - SSCOP SAP interface processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscop_lower.c,v 1.6 1998/04/07 23:21:28 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Local variables + */ +/* + * Stack commands with arg1 containing an buffer pointer + */ +static u_char sscop_buf1[] = { + 0, + 0, /* SSCOP_INIT */ + 0, /* SSCOP_TERM */ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1, /* SSCOP_ESTABLISH_REQ */ + 0, + 1, /* SSCOP_ESTABLISH_RSP */ + 0, + 1, /* SSCOP_RELEASE_REQ */ + 0, + 0, + 1, /* SSCOP_DATA_REQ */ + 0, + 1, /* SSCOP_RESYNC_REQ */ + 0, + 0, /* SSCOP_RESYNC_RSP */ + 0, + 0, + 0, /* SSCOP_RECOVER_RSP */ + 1, /* SSCOP_UNITDATA_REQ */ + 0, + 0, /* SSCOP_RETRIEVE_REQ */ + 0, + 0 +}; + + +/* + * SSCOP Lower Stack Command Handler + * + * This function will receive all of the stack commands issued from the + * layer above SSCOP (ie. using the SSCOP SAP). The appropriate processing + * function will be determined based on the received stack command and the + * current sscop control block state. + * + * Arguments: + * cmd stack command code + * tok session token + * arg1 command specific argument + * arg2 command specific argument + * + * Returns: + * none + * + */ +void +sscop_lower(cmd, tok, arg1, arg2) + int cmd; + void *tok; + int arg1; + int arg2; +{ + struct sscop *sop = (struct sscop *)tok; + void (**stab) __P((struct sscop *, int, int)); + void (*func) __P((struct sscop *, int, int)); + int val; + + ATM_DEBUG5("sscop_lower: cmd=0x%x, sop=0x%x, state=%d, arg1=0x%x, arg2=0x%x\n", + cmd, (int)sop, sop->so_state, arg1, arg2); + + /* + * Validate stack command + */ + val = cmd & STKCMD_VAL_MASK; + if (((u_int)cmd < (u_int)SSCOP_CMD_MIN) || + ((u_int)cmd > (u_int)SSCOP_CMD_MAX) || + ((stab = (sop->so_vers == SSCOP_VERS_QSAAL ? + sscop_qsaal_aatab[val] : + sscop_q2110_aatab[val])) == NULL)) { + log(LOG_ERR, "sscop_lower: unknown cmd 0x%x, sop=0x%x\n", + cmd, (int)sop); + return; + } + + /* + * Validate sscop state + */ + if (sop->so_state > SOS_MAXSTATE) { + log(LOG_ERR, "sscop_lower: invalid state sop=0x%x, state=%d\n", + (int)sop, sop->so_state); + /* + * Release possible buffer + */ + if (sscop_buf1[val]) { + if (arg1) + KB_FREEALL((KBuffer *)arg1); + } + return; + } + + /* + * Validate command/state combination + */ + func = stab[sop->so_state]; + if (func == NULL) { + log(LOG_ERR, + "sscop_lower: invalid cmd/state: sop=0x%x, cmd=0x%x, state=%d\n", + (int)sop, cmd, sop->so_state); + /* + * Release possible buffer + */ + if (sscop_buf1[val]) { + if (arg1) + KB_FREEALL((KBuffer *)arg1); + } + return; + } + + /* + * Call event processing function + */ + (*func)(sop, arg1, arg2); + + return; +} + + +/* + * No-op Processor (no buffers) + * + * Arguments: + * sop pointer to sscop connection block + * arg1 command-specific argument + * arg2 command-specific argument + * + * Returns: + * none + * + */ +void +sscop_aa_noop_0(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + /* + * Nothing to do + */ + return; +} + + +/* + * No-op Processor (arg1 == buffer) + * + * Arguments: + * sop pointer to sscop connection block + * arg1 command-specific argument (buffer pointer) + * arg2 command-specific argument + * + * Returns: + * none + * + */ +void +sscop_aa_noop_1(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * Just free buffer chain + */ + if (arg1) + KB_FREEALL((KBuffer *)arg1); + + return; +} + + +/* + * SSCOP_INIT / SOS_INST Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 command specific argument + * arg2 command specific argument + * + * Returns: + * none + * + */ +void +sscop_init_inst(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + int err; + + /* + * Make ourselves ready and pass on the INIT + */ + sop->so_state = SOS_IDLE; + + /* + * Validate SSCOP version to use + */ + switch ((enum sscop_vers)arg1) { + case SSCOP_VERS_QSAAL: + break; + + case SSCOP_VERS_Q2110: + break; + + default: + sscop_abort(sop, "sscop: bad version\n"); + return; + } + sop->so_vers = (enum sscop_vers)arg1; + + /* + * Copy SSCOP connection parameters to use + */ + sop->so_parm = *(struct sscop_parms *)arg2; + + /* + * Initialize lower layers + */ + STACK_CALL(CPCS_INIT, sop->so_lower, sop->so_tokl, sop->so_connvc, + 0, 0, err); + if (err) { + /* + * Should never happen + */ + sscop_abort(sop, "sscop: INIT failure\n"); + return; + } + return; +} + + +/* + * SSCOP_TERM / SOS_* Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 command specific argument + * arg2 command specific argument + * + * Returns: + * none + * + */ +void +sscop_term_all(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + int err; + + /* + * Set termination state + */ + sop->so_state = SOS_TERM; + + /* + * Pass the TERM down the stack + */ + STACK_CALL(CPCS_TERM, sop->so_lower, sop->so_tokl, sop->so_connvc, + 0, 0, err); + if (err) { + /* + * Should never happen + */ + sscop_abort(sop, "sscop: TERM failure\n"); + return; + } + + /* + * Unlink and free the connection block + */ + UNLINK(sop, struct sscop, sscop_head, so_next); + atm_free((caddr_t)sop); + sscop_vccnt--; + return; +} + diff --git a/sys/netatm/uni/sscop_misc.h b/sys/netatm/uni/sscop_misc.h new file mode 100644 index 0000000..4348cef --- /dev/null +++ b/sys/netatm/uni/sscop_misc.h @@ -0,0 +1,97 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sscop_misc.h,v 1.4 1998/08/26 23:29:19 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP miscellaneous definitions + * + */ + +#ifndef _UNI_SSCOP_MISC_H +#define _UNI_SSCOP_MISC_H + +/* + * SSCOP command definitions + */ +#define SSCOP_CMD_MIN SSCOP_INIT /* Minimum SSCOP CMD value */ +#define SSCOP_CMD_MAX SSCOP_RETRIEVECMP_IND /* Maximum SSCOP CMD value */ +#define SSCOP_CMD_SIZE 36 /* Size of command lookup table */ + + +/* + * Management Errors + */ +#define MAA_ERROR_MIN 'A' +#define MAA_ERROR_MAX 'X' +#define MAA_ERROR_INVAL (MAA_ERROR_MAX + 1) +#define MAA_ERROR_COUNT (MAA_ERROR_MAX - MAA_ERROR_MIN + 2) + + +/* + * SSCOP Sequence Numbers + * + * SSCOP sequence numbers are 24 bit integers using modulo arithmetic. + * The macros below must be used to modify and compare such numbers. + * Comparison of sequence numbers is always relative to some base number (b). + */ +typedef u_int sscop_seq; + +#define SEQ_MOD 0xffffff +#define SEQ_VAL(v) ((v) & SEQ_MOD) +#define SEQ_SET(s,v) ((s) = SEQ_VAL(v)) +#define SEQ_ADD(s,v) (SEQ_VAL((s) + (v))) +#define SEQ_SUB(s,v) (SEQ_VAL((s) - (v))) +#define SEQ_INCR(s,v) ((s) = SEQ_VAL((s) + (v))) +#define SEQ_DECR(s,v) ((s) = SEQ_VAL((s) - (v))) +#define SEQ_EQ(x,y) (SEQ_VAL(x) == SEQ_VAL(y)) +#define SEQ_NEQ(x,y) (SEQ_VAL(x) != SEQ_VAL(y)) +#define SEQ_LT(x,y,b) (SEQ_VAL((x) - (b)) < SEQ_VAL((y) - (b))) +#define SEQ_LEQ(x,y,b) (SEQ_VAL((x) - (b)) <= SEQ_VAL((y) - (b))) +#define SEQ_GT(x,y,b) (SEQ_VAL((x) - (b)) > SEQ_VAL((y) - (b))) +#define SEQ_GEQ(x,y,b) (SEQ_VAL((x) - (b)) >= SEQ_VAL((y) - (b))) + + +/* + * SSCOP Timers + * + * All of the SSCOP timer fields are maintained in terms of clock ticks. + * The timers tick 2 times per second. + */ +#define SSCOP_HZ 2 /* SSCOP ticks per second */ + +#define SSCOP_T_NUM 4 /* Number of timers per connection */ + +#define SSCOP_T_POLL 0 /* Timer_POLL / Timer_KEEP-ALIVE */ +#define SSCOP_T_NORESP 1 /* Timer_NO-RESPONSE */ +#define SSCOP_T_CC 2 /* Timer_CC */ +#define SSCOP_T_IDLE 3 /* Timer_IDLE */ + +#endif /* _UNI_SSCOP_MISC_H */ diff --git a/sys/netatm/uni/sscop_pdu.c b/sys/netatm/uni/sscop_pdu.c new file mode 100644 index 0000000..b9aec03 --- /dev/null +++ b/sys/netatm/uni/sscop_pdu.c @@ -0,0 +1,1237 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sscop_pdu.c,v 1.6 1998/04/07 23:21:36 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP - PDU subroutines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscop_pdu.c,v 1.6 1998/04/07 23:21:36 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + +/* + * Local functions + */ +static KBuffer * sscop_stat_init __P((struct sscop *)); +static KBuffer * sscop_stat_add __P((sscop_seq, KBuffer *)); +static int sscop_stat_end __P((struct sscop *, sscop_seq, + KBuffer *, KBuffer *)); +static int sscop_recv_locate __P((struct sscop *, sscop_seq, + struct pdu_hdr **)); + + +/* + * Build and send BGN PDU + * + * A BGN PDU will be constructed and passed down the protocol stack. + * The SSCOP-UU/N(UU) field is not supported. + * + * Arguments: + * sop pointer to sscop connection control block + * source originator of BGN PDU (Q.SAAL1 only) + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_bgn(sop, source) + struct sscop *sop; + int source; +{ + KBuffer *m; + struct bgn_pdu *bp; + int err; + + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, sizeof(struct bgn_pdu), KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, + KB_BFRLEN(m) - sizeof(struct bgn_pdu))); + KB_LEN(m) = sizeof(struct bgn_pdu); + + /* + * Build PDU + */ + KB_DATASTART(m, bp, struct bgn_pdu *); + *(int *)&bp->bgn_rsvd[0] = 0; + if (sop->so_vers != SSCOP_VERS_QSAAL) + bp->bgn_nsq = sop->so_sendconn; + bp->bgn_nmr = + htonl((PT_BGN << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_rcvmax)); + if ((sop->so_vers == SSCOP_VERS_QSAAL) && + (source == SSCOP_SOURCE_SSCOP)) + bp->bgn_type |= PT_SOURCE_SSCOP; + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send BGAK PDU + * + * A BGAK PDU will be constructed and passed down the protocol stack. + * The SSCOP-UU/N(UU) field is not supported. + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_bgak(sop) + struct sscop *sop; +{ + KBuffer *m; + struct bgak_pdu *bp; + int err; + + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, sizeof(struct bgak_pdu), KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, + KB_BFRLEN(m) - sizeof(struct bgak_pdu))); + KB_LEN(m) = sizeof(struct bgak_pdu); + + /* + * Build PDU + */ + KB_DATASTART(m, bp, struct bgak_pdu *); + bp->bgak_rsvd = 0; + bp->bgak_nmr = + htonl((PT_BGAK << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_rcvmax)); + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send BGREJ PDU + * + * A BGREJ PDU will be constructed and passed down the protocol stack. + * The SSCOP-UU/N(UU) field is not supported. + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_bgrej(sop) + struct sscop *sop; +{ + KBuffer *m; + struct bgrej_pdu *bp; + int err; + + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, sizeof(struct bgrej_pdu), KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, + KB_BFRLEN(m) - sizeof(struct bgrej_pdu))); + KB_LEN(m) = sizeof(struct bgrej_pdu); + + /* + * Build PDU + */ + KB_DATASTART(m, bp, struct bgrej_pdu *); + bp->bgrej_rsvd2 = 0; + *(u_int *)&bp->bgrej_type = htonl((PT_BGREJ << PT_TYPE_SHIFT) | 0); + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send END PDU + * + * An END PDU will be constructed and passed down the protocol stack. + * The SSCOP-UU/N(UU) field is not supported. + * + * Arguments: + * sop pointer to sscop connection control block + * source originator of END PDU + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_end(sop, source) + struct sscop *sop; + int source; +{ + KBuffer *m; + struct end_pdu *ep; + int err; + + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, sizeof(struct end_pdu), KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, + KB_BFRLEN(m) - sizeof(struct end_pdu))); + KB_LEN(m) = sizeof(struct end_pdu); + + /* + * Build PDU + */ + KB_DATASTART(m, ep, struct end_pdu *); + ep->end_rsvd2 = 0; + *(u_int *)&ep->end_type = htonl((PT_END << PT_TYPE_SHIFT) | 0); + if (source == SSCOP_SOURCE_SSCOP) { + ep->end_type |= PT_SOURCE_SSCOP; + sop->so_flags |= SOF_ENDSSCOP; + } else if (source == SSCOP_SOURCE_USER) + sop->so_flags &= ~SOF_ENDSSCOP; + else if ((source == SSCOP_SOURCE_LAST) && + (sop->so_flags & SOF_ENDSSCOP)) + ep->end_type |= PT_SOURCE_SSCOP; + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send ENDAK PDU + * + * An ENDAK PDU will be constructed and passed down the protocol stack. + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_endak(sop) + struct sscop *sop; +{ + KBuffer *m; + struct endak_q2110_pdu *e2p; + struct endak_qsaal_pdu *esp; + int err, size; + + + /* + * Get size of PDU + */ + if (sop->so_vers == SSCOP_VERS_QSAAL) + size = sizeof(struct endak_qsaal_pdu); + else + size = sizeof(struct endak_q2110_pdu); + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, size, KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, KB_BFRLEN(m) - size)); + KB_LEN(m) = size; + + /* + * Build PDU + */ + if (sop->so_vers == SSCOP_VERS_QSAAL) { + KB_DATASTART(m, esp, struct endak_qsaal_pdu *); + *(u_int *)&esp->endak_type = + htonl((PT_ENDAK << PT_TYPE_SHIFT) | 0); + } else { + KB_DATASTART(m, e2p, struct endak_q2110_pdu *); + e2p->endak_rsvd2 = 0; + *(u_int *)&e2p->endak_type = + htonl((PT_ENDAK << PT_TYPE_SHIFT) | 0); + } + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send RS PDU + * + * A RS PDU will be constructed and passed down the protocol stack. + * The SSCOP-UU/N(UU) field is not supported. + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_rs(sop) + struct sscop *sop; +{ + KBuffer *m; + struct rs_pdu *rp; + int err; + + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, sizeof(struct rs_pdu), KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, + KB_BFRLEN(m) - sizeof(struct rs_pdu))); + KB_LEN(m) = sizeof(struct rs_pdu); + + /* + * Build PDU + */ + KB_DATASTART(m, rp, struct rs_pdu *); + *(int *)&rp->rs_rsvd[0] = 0; + if (sop->so_vers != SSCOP_VERS_QSAAL) { + rp->rs_nsq = sop->so_sendconn; + rp->rs_nmr = htonl((PT_RS << PT_TYPE_SHIFT) | + SEQ_VAL(sop->so_rcvmax)); + } else { + rp->rs_nmr = htonl((PT_RS << PT_TYPE_SHIFT) | 0); + } + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send RSAK PDU + * + * An RSAK PDU will be constructed and passed down the protocol stack. + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_rsak(sop) + struct sscop *sop; +{ + KBuffer *m; + struct rsak_q2110_pdu *r2p; + struct rsak_qsaal_pdu *rsp; + int err, size; + + + /* + * Get size of PDU + */ + if (sop->so_vers == SSCOP_VERS_QSAAL) + size = sizeof(struct rsak_qsaal_pdu); + else + size = sizeof(struct rsak_q2110_pdu); + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, size, KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, KB_BFRLEN(m) - size)); + KB_LEN(m) = size; + + /* + * Build PDU + */ + if (sop->so_vers == SSCOP_VERS_QSAAL) { + KB_DATASTART(m, rsp, struct rsak_qsaal_pdu *); + *(u_int *)&rsp->rsaks_type = + htonl((PT_RSAK << PT_TYPE_SHIFT) | 0); + } else { + KB_DATASTART(m, r2p, struct rsak_q2110_pdu *); + r2p->rsak_rsvd = 0; + r2p->rsak_nmr = htonl((PT_RSAK << PT_TYPE_SHIFT) | + SEQ_VAL(sop->so_rcvmax)); + } + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send ER PDU + * + * An ER PDU will be constructed and passed down the protocol stack. + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_er(sop) + struct sscop *sop; +{ + KBuffer *m; + struct er_pdu *ep; + int err; + + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, sizeof(struct er_pdu), KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, + KB_BFRLEN(m) - sizeof(struct er_pdu))); + KB_LEN(m) = sizeof(struct er_pdu); + + /* + * Build PDU + */ + KB_DATASTART(m, ep, struct er_pdu *); + *(int *)&ep->er_rsvd[0] = 0; + ep->er_nsq = sop->so_sendconn; + ep->er_nmr = htonl((PT_ER << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_rcvmax)); + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send ERAK PDU + * + * An ERAK PDU will be constructed and passed down the protocol stack. + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_erak(sop) + struct sscop *sop; +{ + KBuffer *m; + struct erak_pdu *ep; + int err; + + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, sizeof(struct erak_pdu), KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, + KB_BFRLEN(m) - sizeof(struct erak_pdu))); + KB_LEN(m) = sizeof(struct erak_pdu); + + /* + * Build PDU + */ + KB_DATASTART(m, ep, struct erak_pdu *); + ep->erak_rsvd = 0; + ep->erak_nmr = htonl((PT_ERAK << PT_TYPE_SHIFT) | + SEQ_VAL(sop->so_rcvmax)); + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send POLL PDU + * + * A POLL PDU will be constructed and passed down the protocol stack. + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_poll(sop) + struct sscop *sop; +{ + KBuffer *m; + struct poll_pdu *pp; + int err; + + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, sizeof(struct poll_pdu), KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, + KB_BFRLEN(m) - sizeof(struct poll_pdu))); + KB_LEN(m) = sizeof(struct poll_pdu); + + /* + * Build PDU + */ + KB_DATASTART(m, pp, struct poll_pdu *); + pp->poll_nps = htonl(SEQ_VAL(sop->so_pollsend)); + pp->poll_ns = htonl((PT_POLL << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_send)); + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * STAT PDU Construction - Initialize for new PDU + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * addr pointer to initialized buffer + * 0 unable to allocate buffer + * + */ +static KBuffer * +sscop_stat_init(sop) + struct sscop *sop; +{ + KBuffer *m; + +#define STAT_INIT_SIZE (sizeof(struct stat_pdu) + 2 * sizeof(sscop_seq)) + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, STAT_INIT_SIZE, KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (0); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, sop->so_headout < (KB_BFRLEN(m) - STAT_INIT_SIZE) ? + sop->so_headout : 0); + KB_LEN(m) = 0; + + return (m); +#undef STAT_INIT_SIZE +} + + +/* + * STAT PDU Construction - Add List Element + * + * Arguments: + * elem sequence number to add to list + * m pointer to current buffer + * + * Returns: + * addr pointer to current buffer (updated) + * 0 buffer allocation failure + * + */ +static KBuffer * +sscop_stat_add(elem, m) + sscop_seq elem; + KBuffer *m; +{ + KBuffer *n; + sscop_seq *sp; + int space; + + /* + * See if new element will fit in current buffer + */ + KB_TAILROOM(m, space); + if (space < sizeof(elem)) { + + /* + * Nope, so get another buffer + */ + KB_ALLOC(n, sizeof(elem), KB_F_NOWAIT, KB_T_DATA); + if (n == NULL) + return (0); + + /* + * Link in new buffer + */ + KB_LINK(n, m); + KB_LEN(n) = 0; + m = n; + } + + /* + * Add new element + */ + KB_DATAEND(m, sp, sscop_seq *); + *sp = htonl(elem); + KB_LEN(m) += sizeof (elem); + return (m); +} + + +/* + * STAT PDU Construction - Add Trailer and Send + * + * Arguments: + * sop pointer to sscop connection control block + * nps received poll sequence number (POLL.N(PS)) + * head pointer to head of buffer chain + * m pointer to current (last) buffer + * + * Returns: + * 0 STAT successfully sent + * else unable to send STAT or truncated STAT was sent - buffer freed + * + */ +static int +sscop_stat_end(sop, nps, head, m) + struct sscop *sop; + sscop_seq nps; + KBuffer *head; + KBuffer *m; +{ + struct stat_pdu *sp; + KBuffer *n; + int err, space, trunc = 0; + + /* + * See if PDU trailer will fit in current buffer + */ + KB_TAILROOM(m, space); + if (space < sizeof(struct stat_pdu)) { + + /* + * Doesn't fit, so get another buffer + */ + KB_ALLOC(n, sizeof(struct stat_pdu), KB_F_NOWAIT, KB_T_DATA); + if (n == NULL) { + /* + * Out of buffers - truncate elements and send + * what we can, but tell caller that we can't + * send any more segments. + */ + trunc = 1; + do { + KB_LEN(m) -= sizeof(sscop_seq); + space += sizeof(sscop_seq); + } while (space < sizeof(struct stat_pdu)); + } else { + /* + * Link in new buffer + */ + KB_LINK(n, m); + KB_LEN(n) = 0; + m = n; + } + } + + /* + * Build PDU trailer + */ + KB_DATAEND(m, sp, struct stat_pdu *); + sp->stat_nps = htonl(nps); + sp->stat_nmr = htonl(sop->so_rcvmax); + sp->stat_nr = htonl(sop->so_rcvnext); + sp->stat_type = PT_STAT; + KB_LEN(m) += sizeof(struct stat_pdu); + + /* + * Finally, send the STAT + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)head, 0, err); + + if (err) { + /* + * We lie about the STACK_CALL failing... + */ + KB_FREEALL(head); + } + + if (trunc) + return (1); + else + return (0); +} + + +/* + * Check for PDU in Receive Queue + * + * A receive queue will be searched for an SD PDU matching the requested + * sequence number. The caller must supply a pointer to the address of the + * PDU in the particular receive queue at which to begin the search. This + * function will update that pointer as it traverses the queue. + * + * Arguments: + * sop pointer to sscop connection control block + * seq sequence number of PDU to locate + * currp address of pointer to PDU in receive queue to start search + * + * Returns: + * 0 reqeusted PDU not in receive queue + * 1 requested PDU located in receive queue + * + */ +static int +sscop_recv_locate(sop, seq, currp) + struct sscop *sop; + sscop_seq seq; + struct pdu_hdr **currp; +{ + sscop_seq cs; + + /* + * Search queue until we know the answer + */ + while (1) { + /* + * If we're at the end of the queue, the PDU isn't there + */ + if (*currp == NULL) + return (0); + + /* + * Get the current PDU sequence number + */ + cs = (*currp)->ph_ns; + + /* + * See if we're at the requested PDU + */ + if (seq == cs) + return (1); + + /* + * If we're past the requested seq number, + * the PDU isn't there + */ + if (SEQ_LT(seq, cs, sop->so_rcvnext)) + return (0); + + /* + * Go to next PDU and keep looking + */ + *currp = (*currp)->ph_recv_lk; + } +} + + +/* + * Build and send STAT PDU + * + * A STAT PDU will be constructed and passed down the protocol stack. + * + * Arguments: + * sop pointer to sscop connection control block + * nps received poll sequence number (POLL.N(PS)) + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send complete pdu + * + */ +int +sscop_send_stat(sop, nps) + struct sscop *sop; + sscop_seq nps; +{ + KBuffer *head, *curr, *n; + struct pdu_hdr *rq = sop->so_recv_hd; + sscop_seq i; + sscop_seq vrh = sop->so_rcvhigh; + sscop_seq vrr = sop->so_rcvnext; + int len = 0; + + /* + * Initialize for start of STAT PDU + */ + head = sscop_stat_init(sop); + if (head == NULL) + return (1); + curr = head; + + /* + * Start with first PDU not yet received + */ + i = vrr; + + /* + * Keep looping until we get to last sent PDU + */ + while (i != vrh) { + + /* + * Find next missing PDU + */ + while (SEQ_LT(i, vrh, vrr) && sscop_recv_locate(sop, i, &rq)) { + SEQ_INCR(i, 1); + } + + /* + * Add odd (start of missing gap) STAT element + */ + n = sscop_stat_add(i, curr); + if (n == NULL) { + goto nobufs; + } + curr = n; + len++; + + /* + * Have we reached the last sent PDU sequence number?? + */ + if (i == vrh) { + /* + * Yes, then we're done, send STAT + */ + break; + } + + /* + * Have we reached the max STAT size yet?? + */ + if (len >= PDU_MAX_ELEM) { + /* + * Yes, send this STAT segment + */ + if (sscop_stat_end(sop, nps, head, curr)) { + return (1); + } + + /* + * Start a new segment + */ + head = sscop_stat_init(sop); + if (head == NULL) + return (1); + curr = head; + + /* + * Restart missing gap + */ + curr = sscop_stat_add(i, curr); + if (curr == NULL) { + KB_FREEALL(head); + return (1); + } + len = 1; + } + + /* + * Now find the end of the missing gap + */ + do { + SEQ_INCR(i, 1); + } while (SEQ_LT(i, vrh, vrr) && + (sscop_recv_locate(sop, i, &rq) == 0)); + + /* + * Add even (start of received gap) STAT element + */ + n = sscop_stat_add(i, curr); + if (n == NULL) { + goto nobufs; + } + curr = n; + len++; + } + + /* + * Finally, send the STAT PDU (or last STAT segment) + */ + if (sscop_stat_end(sop, nps, head, curr)) { + return (1); + } + + return (0); + +nobufs: + /* + * Send a truncated STAT PDU + */ + sscop_stat_end(sop, nps, head, curr); + + return (1); +} + + +/* + * Build and send USTAT PDU + * + * A USTAT PDU will be constructed and passed down the protocol stack. + * + * Arguments: + * sop pointer to sscop connection control block + * ns sequence number for second list element + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu + * + */ +int +sscop_send_ustat(sop, ns) + struct sscop *sop; + sscop_seq ns; +{ + KBuffer *m; + struct ustat_pdu *up; + int err; + + + /* + * Get buffer for PDU + */ + KB_ALLOCPKT(m, sizeof(struct ustat_pdu), KB_F_NOWAIT, KB_T_HEADER); + if (m == NULL) + return (1); + + /* + * Setup buffer controls + */ + KB_HEADSET(m, MIN(sop->so_headout, + KB_BFRLEN(m) - sizeof(struct ustat_pdu))); + KB_LEN(m) = sizeof(struct ustat_pdu); + + /* + * Build PDU + */ + KB_DATASTART(m, up, struct ustat_pdu *); + up->ustat_le1 = htonl(SEQ_VAL(sop->so_rcvhigh)); + up->ustat_le2 = htonl(SEQ_VAL(ns)); + up->ustat_nmr = htonl(SEQ_VAL(sop->so_rcvmax)); + up->ustat_nr = + htonl((PT_USTAT << PT_TYPE_SHIFT) | SEQ_VAL(sop->so_rcvnext)); + + /* + * Send PDU towards peer + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + + if (err) + KB_FREEALL(m); + + return (err); +} + + +/* + * Build and send UD PDU + * + * A UD PDU will be constructed and passed down the protocol stack. + * + * Arguments: + * sop pointer to sscop connection control block + * m pointer to user data buffer chain + * + * Returns: + * 0 PDU successfully built and passed down the stack + * else unable to build or send pdu (buffer released) + * + */ +int +sscop_send_ud(sop, m) + struct sscop *sop; + KBuffer *m; +{ + KBuffer *ml, *n; + int len = 0, err; + int pad, trlen, space; + u_char *cp; + + /* + * Count data and get to last buffer in chain + */ + for (ml = m; ; ml = KB_NEXT(ml)) { + len += KB_LEN(ml); + if (KB_NEXT(ml) == NULL) + break; + } + + /* + * Verify data length + */ + if (len > sop->so_parm.sp_maxinfo) { + KB_FREEALL(m); + sscop_abort(sop, "sscop: maximum unitdata size exceeded\n"); + return (1); + } + + /* + * Figure out how much padding we'll need + */ + pad = ((len + (PDU_PAD_ALIGN - 1)) & ~(PDU_PAD_ALIGN - 1)) - len; + trlen = pad + sizeof(struct ud_pdu); + + /* + * Get space for PDU trailer and padding + */ + KB_TAILROOM(ml, space); + if (space < trlen) { + /* + * Allocate & link buffer for pad and trailer + */ + KB_ALLOC(n, trlen, KB_F_NOWAIT, KB_T_HEADER); + if (n == NULL) + return (1); + + KB_LEN(n) = 0; + KB_LINK(n, ml); + ml = n; + } + + /* + * Build the PDU trailer + * + * Since we can't be sure of alignment in the buffers, we + * have to move this a byte at a time. + */ + KB_DATAEND(ml, cp, u_char *); + cp += pad; + *cp++ = (pad << PT_PAD_SHIFT) | PT_UD; + KM_ZERO(cp, 3); + KB_LEN(ml) += trlen; + + /* + * Now pass PDU down the stack + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + return (1); + } + + return (0); +} + + +/* + * Print an SSCOP PDU + * + * Arguments: + * sop pointer to sscop connection control block + * m pointer to pdu buffer chain + * msg pointer to message string + * + * Returns: + * none + * + */ +void +sscop_pdu_print(sop, m, msg) + struct sscop *sop; + KBuffer *m; + char *msg; +{ + char buf[128]; + struct vccb *vcp; + + vcp = sop->so_connvc->cvc_vcc; + sprintf(buf, "sscop %s: vcc=(%d,%d)\n", msg, vcp->vc_vpi, vcp->vc_vci); + atm_pdu_print(m, buf); +} + diff --git a/sys/netatm/uni/sscop_pdu.h b/sys/netatm/uni/sscop_pdu.h new file mode 100644 index 0000000..387a602 --- /dev/null +++ b/sys/netatm/uni/sscop_pdu.h @@ -0,0 +1,317 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sscop_pdu.h,v 1.3 1997/05/06 22:20:15 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP Protocol Data Unit (PDU) definitions + * + */ + +#ifndef _UNI_SSCOP_PDU_H +#define _UNI_SSCOP_PDU_H + +/* + * SSCOP PDU Constants + */ +#define PDU_MIN_LEN 4 /* Minimum PDU length */ +#define PDU_LEN_MASK 3 /* PDU length must be 32-bit aligned */ +#define PDU_ADDR_MASK 3 /* PDUs must be 32-bit aligned */ +#define PDU_SEQ_MASK 0x00ffffff /* Mask for 24-bit sequence values */ +#define PDU_MAX_INFO 65528 /* Maximum length of PDU info field */ +#define PDU_MAX_UU 65524 /* Maximum length of SSCOP-UU field */ +#define PDU_MAX_STAT 65520 /* Maximum length of STAT list */ +#define PDU_MAX_ELEM 67 /* Maximum elements sent in STAT */ +#define PDU_PAD_ALIGN 4 /* I-field padding alignment */ + + +/* + * PDU Queueing Header + * + * There will be a queueing header tacked on to the front of each + * buffer chain that is placed on any of the sscop SD PDU queues (not + * including the SD transmission queue). Note that this header will + * not be included in the buffer data length/offset fields. + */ +struct pdu_hdr { + union { + struct pdu_hdr *phu_pack_lk; /* Pending ack queue link */ + struct pdu_hdr *phu_recv_lk; /* Receive queue link */ + } ph_u; + struct pdu_hdr *ph_rexmit_lk; /* Retranmit queue link */ + sscop_seq ph_ns; /* SD.N(S) - SD's sequence number */ + sscop_seq ph_nps; /* SD.N(PS) - SD's poll sequence */ + KBuffer *ph_buf; /* Pointer to containing buffer */ +}; +#define ph_pack_lk ph_u.phu_pack_lk +#define ph_recv_lk ph_u.phu_recv_lk + + +/* + * SSCOP PDU formats + * + * N.B. - all SSCOP PDUs are trailer oriented (don't ask me...) + */ + +/* + * PDU Type Fields + */ +#define PT_PAD_MASK 0xc0 /* Pad length mask */ +#define PT_PAD_SHIFT 6 /* Pad byte shift count */ +#define PT_SOURCE_SSCOP 0x10 /* Source = SSCOP */ +#define PT_TYPE_MASK 0x0f /* Type mask */ +#define PT_TYPE_MAX 0x0f /* Maximum pdu type */ +#define PT_TYPE_SHIFT 24 /* Type word shift count */ + +#define PT_BGN 0x01 /* Begin */ +#define PT_BGAK 0x02 /* Begin Acknowledge */ +#define PT_BGREJ 0x07 /* Begin Reject */ +#define PT_END 0x03 /* End */ +#define PT_ENDAK 0x04 /* End Acknowledge */ +#define PT_RS 0x05 /* Resynchronization */ +#define PT_RSAK 0x06 /* Resynchronization Acknowledge */ +#define PT_ER 0x09 /* Error Recovery */ +#define PT_ERAK 0x0f /* Error Recovery Acknowledge */ +#define PT_SD 0x08 /* Sequenced Data */ +#define PT_SDP 0x09 /* Sequenced Data with Poll */ +#define PT_POLL 0x0a /* Status Request */ +#define PT_STAT 0x0b /* Solicited Status Response */ +#define PT_USTAT 0x0c /* Unsolicited Status Response */ +#define PT_UD 0x0d /* Unnumbered Data */ +#define PT_MD 0x0e /* Management Data */ + +/* + * Begin PDU + */ +struct bgn_pdu { + u_char bgn_rsvd[3]; /* Reserved */ + u_char bgn_nsq; /* N(SQ) */ + union { + u_char bgnu_type; /* PDU type, etc */ + sscop_seq bgnu_nmr; /* N(MR) */ + } bgn_u; +}; +#define bgn_type bgn_u.bgnu_type +#define bgn_nmr bgn_u.bgnu_nmr + +/* + * Begin Acknowledge PDU + */ +struct bgak_pdu { + int bgak_rsvd; /* Reserved */ + union { + u_char bgaku_type; /* PDU type, etc */ + sscop_seq bgaku_nmr; /* N(MR) */ + } bgak_u; +}; +#define bgak_type bgak_u.bgaku_type +#define bgak_nmr bgak_u.bgaku_nmr + +/* + * Begin Reject PDU + */ +struct bgrej_pdu { + int bgrej_rsvd2; /* Reserved */ + u_char bgrej_type; /* PDU type, etc */ + u_char bgrej_rsvd1[3]; /* Reserved */ +}; + +/* + * End PDU + */ +struct end_pdu { + int end_rsvd2; /* Reserved */ + u_char end_type; /* PDU type, etc */ + u_char end_rsvd1[3]; /* Reserved */ +}; + +/* + * End Acknowledge PDU (Q.2110) + */ +struct endak_q2110_pdu { + int endak_rsvd2; /* Reserved */ + u_char endak_type; /* PDU type, etc */ + u_char endak_rsvd1[3]; /* Reserved */ +}; + +/* + * End Acknowledge PDU (Q.SAAL) + */ +struct endak_qsaal_pdu { + u_char endak_type; /* PDU type, etc */ + u_char endak_rsvd[3]; /* Reserved */ +}; + +/* + * Resynchronization PDU + */ +struct rs_pdu { + char rs_rsvd[3]; /* Reserved */ + u_char rs_nsq; /* N(SQ) */ + union { + u_char rsu_type; /* PDU type, etc */ + sscop_seq rsu_nmr; /* N(MR) */ + } rs_u; +}; +#define rs_type rs_u.rsu_type +#define rs_nmr rs_u.rsu_nmr + +/* + * Resynchronization Acknowledge PDU (Q.2110) + */ +struct rsak_q2110_pdu { + int rsak_rsvd; /* Reserved */ + union { + u_char rsaku_type; /* PDU type, etc */ + sscop_seq rsaku_nmr; /* N(MR) */ + } rsak_u; +}; +#define rsak2_type rsak_u.rsaku_type +#define rsak_nmr rsak_u.rsaku_nmr + +/* + * Resynchronization Acknowledge PDU (Q.SAAL) + */ +struct rsak_qsaal_pdu { + u_char rsaks_type; /* PDU type, etc */ + u_char rsak_rsvd[3]; /* Reserved */ +}; + +/* + * Error Recovery PDU + */ +struct er_pdu { + char er_rsvd[3]; /* Reserved */ + u_char er_nsq; /* N(SQ) */ + union { + u_char eru_type; /* PDU type, etc */ + sscop_seq eru_nmr; /* N(MR) */ + } er_u; +}; +#define er_type er_u.eru_type +#define er_nmr er_u.eru_nmr + +/* + * Error Recovery Acknowledge PDU + */ +struct erak_pdu { + int erak_rsvd; /* Reserved */ + union { + u_char eraku_type; /* PDU type, etc */ + sscop_seq eraku_nmr; /* N(MR) */ + } erak_u; +}; +#define erak_type erak_u.eraku_type +#define erak_nmr erak_u.eraku_nmr + +/* + * Sequenced Data PDU + */ +struct sd_pdu { + union { + u_char sdu_type; /* PDU type, etc */ + sscop_seq sdu_ns; /* N(S) */ + } sd_u; +}; +#define sd_type sd_u.sdu_type +#define sd_ns sd_u.sdu_ns + +/* + * Sequenced Data with Poll PDU + */ +struct sdp_pdu { + sscop_seq sdp_nps; /* N(PS) */ + union { + u_char sdpu_type; /* PDU type, etc */ + sscop_seq sdpu_ns; /* N(S) */ + } sdp_u; +}; +#define sdp_type sdp_u.sdpu_type +#define sdp_ns sdp_u.sdpu_ns + +/* + * Poll PDU + */ +struct poll_pdu { + sscop_seq poll_nps; /* N(PS) */ + union { + u_char pollu_type; /* PDU type, etc */ + sscop_seq pollu_ns; /* N(S) */ + } poll_u; +}; +#define poll_type poll_u.pollu_type +#define poll_ns poll_u.pollu_ns + +/* + * Solicited Status PDU + */ +struct stat_pdu { + sscop_seq stat_nps; /* N(PS) */ + sscop_seq stat_nmr; /* N(MR) */ + union { + u_char statu_type; /* PDU type, etc */ + sscop_seq statu_nr; /* N(R) */ + } stat_u; +}; +#define stat_type stat_u.statu_type +#define stat_nr stat_u.statu_nr + +/* + * Unsolicited Status PDU + */ +struct ustat_pdu { + sscop_seq ustat_le1; /* List element 1 */ + sscop_seq ustat_le2; /* List element 2 */ + sscop_seq ustat_nmr; /* N(MR) */ + union { + u_char ustatu_type; /* PDU type, etc */ + sscop_seq ustatu_nr; /* N(R) */ + } ustat_u; +}; +#define ustat_type ustat_u.ustatu_type +#define ustat_nr ustat_u.ustatu_nr + +/* + * Unit Data PDU + */ +struct ud_pdu { + u_char ud_type; /* PDU type, etc */ + u_char ud_rsvd[3]; /* Reserved */ +}; + +/* + * Management Data PDU + */ +struct md_pdu { + u_char md_type; /* PDU type, etc */ + u_char md_rsvd[3]; /* Reserved */ +}; + +#endif /* _UNI_SSCOP_PDU_H */ diff --git a/sys/netatm/uni/sscop_sigaa.c b/sys/netatm/uni/sscop_sigaa.c new file mode 100644 index 0000000..8f347ce --- /dev/null +++ b/sys/netatm/uni/sscop_sigaa.c @@ -0,0 +1,449 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sscop_sigaa.c,v 1.1 1998/04/07 23:15:11 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP Common - Process AA-signals (SAP_SSCOP) + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscop_sigaa.c,v 1.1 1998/04/07 23:15:11 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * SSCOP_ESTABLISH_REQ / SOS_IDLE Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing SSCOP-UU data + * arg2 buffer release parameter + * + * Returns: + * none + * + */ +void +sscop_estreq_idle(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * We don't support SSCOP-UU data + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * We currently only support BR=YES + */ + if (arg2 != SSCOP_BR_YES) { + sscop_abort(sop, "sscop: BR != YES\n"); + return; + } + + /* + * Initialize receiver window + */ + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + + /* + * Send first BGN PDU + */ + sop->so_connctl = 1; + SEQ_INCR(sop->so_sendconn, 1); + (void) sscop_send_bgn(sop, SSCOP_SOURCE_USER); + + /* + * Reset transmitter state + */ + if (sop->so_vers == SSCOP_VERS_Q2110) + q2110_clear_xmit(sop); + else + qsaal1_reset_xmit(sop); + + /* + * Set retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + /* + * Wait for BGAK + */ + sop->so_state = SOS_OUTCONN; + + return; +} + + +/* + * SSCOP_ESTABLISH_RSP / SOS_INCONN Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing SSCOP-UU data + * arg2 buffer release parameter + * + * Returns: + * none + * + */ +void +sscop_estrsp_inconn(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * We don't support SSCOP-UU data + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * We currently only support BR=YES + */ + if (arg2 != SSCOP_BR_YES) { + sscop_abort(sop, "sscop: BR != YES\n"); + return; + } + + if (sop->so_vers == SSCOP_VERS_Q2110) { + /* + * Clear transmitter buffers + */ + q2110_clear_xmit(sop); + + /* + * Initialize state variables + */ + SEQ_SET(sop->so_rcvmax, sop->so_parm.sp_rcvwin); + q2110_init_state(sop); + } else { + /* + * Reset transmitter state + */ + qsaal1_reset_xmit(sop); + } + + /* + * Send BGAK PDU + */ + (void) sscop_send_bgak(sop); + + /* + * Start polling timer + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + + /* + * Start lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * OK, we're ready for data + */ + sop->so_state = SOS_READY; + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; +} + + +/* + * SSCOP_RELEASE_REQ / SOS_OUTCONN Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing SSCOP-UU data + * arg2 unused + * + * Returns: + * none + * + */ +void +sscop_relreq_outconn(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * We don't support SSCOP-UU data + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Clear reestablishment flag + */ + sop->so_flags &= ~SOF_REESTAB; + + /* + * Send first END PDU + */ + sop->so_connctl = 1; + (void) sscop_send_end(sop, SSCOP_SOURCE_USER); + + if (sop->so_vers == SSCOP_VERS_QSAAL) + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Set retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + /* + * Wait for ENDAK + */ + sop->so_state = SOS_OUTDISC; + + return; +} + + +/* + * SSCOP_RELEASE_REQ / SOS_INCONN Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing SSCOP-UU data + * arg2 unused + * + * Returns: + * none + * + */ +void +sscop_relreq_inconn(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * We don't support SSCOP-UU data + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * Return a BGREJ PDU + */ + (void) sscop_send_bgrej(sop); + + /* + * Back to IDLE state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * SSCOP_RELEASE_REQ / SOS_READY Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing SSCOP-UU data + * arg2 unused + * + * Returns: + * none + * + */ +void +sscop_relreq_ready(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + + /* + * We don't support SSCOP-UU data + */ + if (arg1 != SSCOP_UU_NULL) + KB_FREEALL((KBuffer *)arg1); + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Send first END PDU + */ + sop->so_connctl = 1; + (void) sscop_send_end(sop, SSCOP_SOURCE_USER); + + if (sop->so_vers == SSCOP_VERS_Q2110) { + /* + * Clear out appropriate queues + */ + if (sop->so_state == SOS_READY) + q2110_prep_retrieve(sop); + else + sscop_rcvr_drain(sop); + } else { + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + } + + /* + * Set retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + /* + * Wait for ENDAK + */ + sop->so_state = SOS_OUTDISC; + + return; +} + + +/* + * SSCOP_DATA_REQ / SOS_READY Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing assured user data + * arg2 unused + * + * Returns: + * none + * + */ +void +sscop_datreq_ready(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + KBuffer *m = (KBuffer *)arg1; + + /* + * We must have a buffer (even if it contains no data) + */ + if (m == NULL) { + sscop_abort(sop, "sscop_datreq_ready: no buffer\n"); + return; + } + + /* + * Place data at end of transmission queue + */ + KB_QNEXT(m) = NULL; + if (sop->so_xmit_hd == NULL) + sop->so_xmit_hd = m; + else + KB_QNEXT(sop->so_xmit_tl) = m; + sop->so_xmit_tl = m; + + /* + * Service the transmit queues + */ + sscop_service_xmit(sop); + + return; +} + + +/* + * SSCOP_UNITDATA_REQ / SOS_* Command Processor + * + * Arguments: + * sop pointer to sscop connection block + * arg1 pointer to buffer containing unassured user data + * arg2 unused + * + * Returns: + * none + * + */ +void +sscop_udtreq_all(sop, arg1, arg2) + struct sscop *sop; + int arg1; + int arg2; +{ + KBuffer *m = (KBuffer *)arg1; + + /* + * We must have a buffer (even if it contains no data) + */ + if (m == NULL) { + sscop_abort(sop, "sscop_udtreq_all: no buffer\n"); + return; + } + + /* + * Send the data in a UD PDU + */ + (void) sscop_send_ud(sop, m); + + return; +} + diff --git a/sys/netatm/uni/sscop_sigcpcs.c b/sys/netatm/uni/sscop_sigcpcs.c new file mode 100644 index 0000000..a9bf504 --- /dev/null +++ b/sys/netatm/uni/sscop_sigcpcs.c @@ -0,0 +1,2311 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sscop_sigcpcs.c,v 1.2 1998/07/24 20:18:09 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP Common - Process CPCS-signals (SSCOP PDUs) + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscop_sigcpcs.c,v 1.2 1998/07/24 20:18:09 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * No-op Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_noop(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + /* + * Just free PDU + */ + KB_FREEALL(m); + + return; +} + + +/* + * BGN PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgn_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct bgn_pdu *bp = (struct bgn_pdu *)trlr; + int err, source; + + if (sop->so_vers == SSCOP_VERS_Q2110) { + /* + * "Power-up Robustness" option + * + * Accept BGN regardless of BGN.N(SQ) + */ + sop->so_rcvconn = bp->bgn_nsq; + + } else { + /* + * If retransmitted BGN, reject it + */ + if (sscop_is_rexmit(sop, bp->bgn_nsq)) { + KB_FREEALL(m); + (void) sscop_send_bgrej(sop); + return; + } + } + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Get Source value + */ + if (bp->bgn_type & PT_SOURCE_SSCOP) + source = SSCOP_SOURCE_SSCOP; + else + source = SSCOP_SOURCE_USER; + + /* + * Reset receiver state variables + */ + qsaal1_reset_rcvr(sop); + } else + source = 0; + + /* + * Set initial transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); + + /* + * Pass connection request up to user + */ + STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Wait for user's response + */ + sop->so_state = SOS_INCONN; + + return; +} + + +/* + * BGN PDU / SOS_OUTDISC Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgn_outdisc(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct bgn_pdu *bp = (struct bgn_pdu *)trlr; + int err, source; + + /* + * If retransmitted BGN, ACK it and send new END + */ + if (sscop_is_rexmit(sop, bp->bgn_nsq)) { + KB_FREEALL(m); + (void) sscop_send_bgak(sop); + (void) sscop_send_end(sop, SSCOP_SOURCE_LAST); + return; + } + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_CNF, sop->so_upper, sop->so_toku, + sop->so_connvc, 0, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Get Source value + */ + if (bp->bgn_type & PT_SOURCE_SSCOP) + source = SSCOP_SOURCE_SSCOP; + else + source = SSCOP_SOURCE_USER; + + /* + * Reset receiver variables + */ + qsaal1_reset_rcvr(sop); + + } else + source = 0; + + /* + * Tell user about incoming connection + */ + STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Wait for user's response + */ + sop->so_state = SOS_INCONN; + + return; +} + + +/* + * BGN PDU / SOS_OUTRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgn_outresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct bgn_pdu *bp = (struct bgn_pdu *)trlr; + int err, source; + + /* + * If retransmitted BGN, ACK it and send new RS + */ + if (sscop_is_rexmit(sop, bp->bgn_nsq)) { + KB_FREEALL(m); + (void) sscop_send_bgak(sop); + (void) sscop_send_rs(sop); + return; + } + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Get (possible) Source value + */ + if (bp->bgn_type & PT_SOURCE_SSCOP) + source = SSCOP_SOURCE_SSCOP; + else + source = SSCOP_SOURCE_USER; + + /* + * Reset receiver variables + */ + qsaal1_reset_rcvr(sop); + + } else + source = SSCOP_SOURCE_USER; + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Now tell user of a "new" incoming connection + */ + STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Wait for user's response + */ + sop->so_state = SOS_INCONN; + + return; +} + + +/* + * BGN PDU / SOS_INRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgn_inresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct bgn_pdu *bp = (struct bgn_pdu *)trlr; + int err, source; + + /* + * If retransmitted BGN, oops + */ + if (sscop_is_rexmit(sop, bp->bgn_nsq)) { + KB_FREEALL(m); + sscop_maa_error(sop, 'B'); + return; + } + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(bp->bgn_nmr)); + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Get (possible) Source value + */ + if (bp->bgn_type & PT_SOURCE_SSCOP) + source = SSCOP_SOURCE_SSCOP; + else + source = SSCOP_SOURCE_USER; + + /* + * Reset receiver variables + */ + qsaal1_reset_rcvr(sop); + + } else { + /* + * Stop possible retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Drain receiver queues + */ + sscop_rcvr_drain(sop); + + /* + * Tell user current connection has been released + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_USER, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + source = 0; + } + + /* + * Tell user of incoming connection + */ + STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Wait for user's response + */ + sop->so_state = SOS_INCONN; + + return; +} + + +/* + * BGAK PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgak_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'C'); + KB_FREEALL(m); + + return; +} + + +/* + * BGAK PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgak_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_bgak_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + return; +} + + +/* + * BGAK PDU / SOS_OUTCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgak_outconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct bgak_pdu *bp = (struct bgak_pdu *)trlr; + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Initialize transmit window + */ + SEQ_SET(sop->so_sendmax, ntohl(bp->bgak_nmr)); + + /* + * Notify user of connection establishment + */ + if (sop->so_flags & SOF_REESTAB) { + KB_FREEALL(m); + STACK_CALL(SSCOP_ESTABLISH_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + sop->so_flags &= ~SOF_REESTAB; + } else { + STACK_CALL(SSCOP_ESTABLISH_CNF, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + } + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Reset receiver variables + */ + qsaal1_reset_rcvr(sop); + + /* + * Start polling timer + */ + sscop_set_poll(sop); + + /* + * Start lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + } else { + /* + * Initialize state variables + */ + q2110_init_state(sop); + + /* + * Start data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + } + + /* + * OK, we're ready for data + */ + sop->so_state = SOS_READY; + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; +} + + +/* + * BGREJ PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgrej_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'D'); + KB_FREEALL(m); + return; +} + + +/* + * BGREJ PDU / SOS_OUTCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgrej_outconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int source, uu, err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Clear reestablishment flag + */ + sop->so_flags &= ~SOF_REESTAB; + + KB_FREEALL(m); + m = NULL; + uu = SSCOP_UU_NULL; + source = SSCOP_SOURCE_SSCOP; + } else { + uu = (int)m; + source = SSCOP_SOURCE_USER; + } + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, uu, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * BGREJ PDU / SOS_INCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgrej_inconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Report protocol error + */ + sscop_bgrej_error(sop, m, trlr); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * BGREJ PDU / SOS_OUTRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgrej_outresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Report protocol error + */ + sscop_bgrej_error(sop, m, trlr); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + } + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * BGREJ PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_bgrej_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Report protocol error + */ + sscop_bgrej_error(sop, m, trlr); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + } else { + /* + * Clear out appropriate queues + */ + q2110_prep_retrieve(sop); + } + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * END PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_end_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Free buffers + */ + KB_FREEALL(m); + + /* + * Return an ENDAK to peer + */ + (void) sscop_send_endak(sop); + + return; +} + + +/* + * END PDU / SOS_INCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_end_inconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct end_pdu *ep = (struct end_pdu *)trlr; + int err, source; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Acknowledge END + */ + (void) sscop_send_endak(sop); + + /* + * Get Source value + */ + if (ep->end_type & PT_SOURCE_SSCOP) + source = SSCOP_SOURCE_SSCOP; + else + source = SSCOP_SOURCE_USER; + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, source, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * END PDU / SOS_OUTDISC Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_end_outdisc(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Release buffers + */ + KB_FREEALL(m); + + /* + * Acknowledge END + */ + (void) sscop_send_endak(sop); + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_CNF, sop->so_upper, sop->so_toku, + sop->so_connvc, 0, 0, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * ENDAK PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_endak_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'F'); + KB_FREEALL(m); + + return; +} + + +/* + * ENDAK PDU / SOS_INCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_endak_inconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Report protocol error + */ + sscop_endak_error(sop, m, trlr); + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * ENDAK PDU / SOS_OUTDISC Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_endak_outdisc(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Release buffers + */ + KB_FREEALL(m); + + /* + * Notify user of connection termination + */ + STACK_CALL(SSCOP_RELEASE_CNF, sop->so_upper, sop->so_toku, + sop->so_connvc, 0, 0, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * ENDAK PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_endak_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Report protocol error + */ + sscop_endak_error(sop, m, trlr); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + } else { + /* + * Clear out appropriate queues + */ + q2110_prep_retrieve(sop); + } + + /* + * Back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * RS PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_rs_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'J'); + KB_FREEALL(m); + + return; +} + + +/* + * RS PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_rs_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Report error condition + */ + sscop_rs_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + return; +} + + +/* + * RSAK PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_rsak_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'K'); + KB_FREEALL(m); + + return; +} + + +/* + * RSAK PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_rsak_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Report error condition + */ + sscop_rsak_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + return; +} + + +/* + * RSAK PDU / SOS_OUTRESYN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_rsak_outresyn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct rsak_q2110_pdu *rp = (struct rsak_q2110_pdu *)trlr; + int err; + + /* + * Stop retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = 0; + + /* + * Notify user of resynchronization completion + */ + STACK_CALL(SSCOP_RESYNC_CNF, sop->so_upper, sop->so_toku, + sop->so_connvc, 0, 0, err); + if (err) { + KB_FREEALL(m); + sscop_abort(sop, "stack memory\n"); + return; + } + + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Start the polling timer + */ + sscop_set_poll(sop); + + /* + * Start lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + } else { + /* + * Initialize state variables + */ + SEQ_SET(sop->so_sendmax, ntohl(rp->rsak_nmr)); + q2110_init_state(sop); + + /* + * Start data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + } + + /* + * Free buffers + */ + KB_FREEALL(m); + + /* + * Now go back to data transfer state + */ + sop->so_state = SOS_READY; + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; +} + + +/* + * SD PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_sd_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'A'); + KB_FREEALL(m); + + return; +} + + +/* + * SD PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_sd_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_sd_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + return; +} + + +/* + * SD PDU / SOS_INCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_sd_inconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Record error condition + */ + sscop_sd_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Go back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * POLL PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_poll_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'G'); + KB_FREEALL(m); + + return; +} + + +/* + * POLL PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_poll_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Report error condition + */ + sscop_poll_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + return; +} + + +/* + * POLL PDU / SOS_INCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_poll_inconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Record error condition + */ + sscop_poll_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Go back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * STAT PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_stat_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'H'); + KB_FREEALL(m); + + return; +} + + +/* + * STAT PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_stat_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Report error condition + */ + sscop_stat_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + return; +} + + +/* + * STAT PDU / SOS_INCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_stat_inconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Record error condition + */ + sscop_stat_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Go back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * STAT PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_stat_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct stat_pdu *sp = (struct stat_pdu *)trlr; + struct pdu_hdr *php; + KBuffer *m0 = m; + sscop_seq seq1, seq2, opa; + int cnt = 0; + + NTOHL(sp->stat_nps); + NTOHL(sp->stat_nmr); + NTOHL(sp->stat_nr); + + /* + * Validate peer's received poll sequence number + */ + if (SEQ_GT(sop->so_pollack, sp->stat_nps, sop->so_pollack) || + SEQ_GT(sp->stat_nps, sop->so_pollsend, sop->so_pollack)) { + /* + * Bad poll sequence number + */ + sscop_maa_error(sop, 'R'); + goto goterr; + } + + /* + * Validate peer's current receive data sequence number + */ + if (SEQ_GT(sop->so_ack, sp->stat_nr, sop->so_ack) || + SEQ_GT(sp->stat_nr, sop->so_send, sop->so_ack)) { + /* + * Bad data sequence number + */ + sscop_maa_error(sop, 'S'); + goto goterr; + } + + /* + * Free acknowledged PDUs + */ + for (seq1 = sop->so_ack, SEQ_SET(seq2, sp->stat_nr); + SEQ_LT(seq1, seq2, sop->so_ack); + SEQ_INCR(seq1, 1)) { + sscop_pack_free(sop, seq1); + } + + /* + * Update transmit state variables + */ + opa = sop->so_pollack; + sop->so_ack = seq2; + SEQ_SET(sop->so_pollack, sp->stat_nps); + SEQ_SET(sop->so_sendmax, sp->stat_nmr); + + /* + * Get first element in STAT list + */ + while (m && (KB_LEN(m) == 0)) + m = KB_NEXT(m); + if (m == NULL) + goto done; + m = sscop_stat_getelem(m, &seq1); + + /* + * Make sure there's a second element too + */ + if (m == NULL) + goto done; + + /* + * Validate first element (start of missing pdus) + */ + if (SEQ_GT(sop->so_ack, seq1, sop->so_ack) || + SEQ_GEQ(seq1, sop->so_send, sop->so_ack)) { + /* + * Bad element sequence number + */ + sscop_maa_error(sop, 'S'); + goto goterr; + } + + /* + * Loop thru all STAT elements in list + */ + while (m) { + /* + * Get next even element (start of received pdus) + */ + m = sscop_stat_getelem(m, &seq2); + + /* + * Validate seqence number + */ + if (SEQ_GEQ(seq1, seq2, sop->so_ack) || + SEQ_GT(seq2, sop->so_send, sop->so_ack)) { + /* + * Bad element sequence number + */ + sscop_maa_error(sop, 'S'); + goto goterr; + } + + /* + * Process each missing sequence number in this gap + */ + while (SEQ_LT(seq1, seq2, sop->so_ack)) { + /* + * Find corresponding SD PDU on pending ack queue + */ + php = sscop_pack_locate(sop, seq1); + if (php == NULL) { + sscop_maa_error(sop, 'S'); + goto goterr; + } + + /* + * Retransmit this SD PDU only if it was last sent + * during an earlier poll sequence and it's not + * already scheduled for retranmission. + */ + if (SEQ_LT(php->ph_nps, sp->stat_nps, opa) && + (php->ph_rexmit_lk == NULL) && + (sop->so_rexmit_tl != php)) { + /* + * Put PDU on retransmit queue and schedule + * transmit servicing + */ + sscop_rexmit_insert(sop, php); + sop->so_flags |= SOF_XMITSRVC; + cnt++; + } + + /* + * Bump to next sequence number + */ + SEQ_INCR(seq1, 1); + } + + /* + * Now process series of acknowledged PDUs + * + * Get next odd element (start of missing pdus), + * but make sure there is one and that it's valid + */ + if (m == NULL) + goto done; + m = sscop_stat_getelem(m, &seq2); + if (SEQ_GEQ(seq1, seq2, sop->so_ack) || + SEQ_GT(seq2, sop->so_send, sop->so_ack)) { + /* + * Bad element sequence number + */ + sscop_maa_error(sop, 'S'); + goto goterr; + } + + /* + * Process each acked sequence number + */ + while (SEQ_LT(seq1, seq2, sop->so_ack)) { + /* + * Can we clear transmit buffers ?? + */ + if ((sop->so_flags & SOF_NOCLRBUF) == 0) { + /* + * Yes, free acked buffers + */ + sscop_pack_free(sop, seq1); + } + + /* + * Bump to next sequence number + */ + SEQ_INCR(seq1, 1); + } + } + +done: + /* + * Free PDU buffer chain + */ + KB_FREEALL(m0); + + /* + * Report retransmitted PDUs + */ + if (cnt) + sscop_maa_error(sop, 'V'); + + /* + * Record transmit window closed transitions + */ + if (SEQ_LT(sop->so_send, sop->so_sendmax, sop->so_ack)) { + if (sop->so_flags & SOF_NOCREDIT) { + sop->so_flags &= ~SOF_NOCREDIT; + sscop_maa_error(sop, 'X'); + } + } else { + if ((sop->so_flags & SOF_NOCREDIT) == 0) { + sop->so_flags |= SOF_NOCREDIT; + sscop_maa_error(sop, 'W'); + } + } + + if (sop->so_vers == SSCOP_VERS_QSAAL) + /* + * Restart lost poll/stat timer + */ + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + else { + /* + * Determine new polling phase + */ + if ((sop->so_timer[SSCOP_T_POLL] != 0) && + ((sop->so_flags & SOF_KEEPALIVE) == 0)) { + /* + * Remain in active phase - reset NO-RESPONSE timer + */ + sop->so_timer[SSCOP_T_NORESP] = + sop->so_parm.sp_timeresp; + + } else if (sop->so_timer[SSCOP_T_IDLE] == 0) { + /* + * Go from transient to idle phase + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + sop->so_timer[SSCOP_T_NORESP] = 0; + sop->so_timer[SSCOP_T_IDLE] = sop->so_parm.sp_timeidle; + } + } + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; + +goterr: + /* + * Protocol/parameter error encountered + */ + + /* + * Free PDU buffer chain + */ + KB_FREEALL(m0); + + if (sop->so_vers == SSCOP_VERS_QSAAL) + /* + * Reestablish a new connection + */ + qsaal1_reestablish(sop); + else + /* + * Initiate error recovery + */ + q2110_error_recovery(sop); + + return; +} + + +/* + * USTAT PDU / Protocol Error + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_ustat_error(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Record error condition + */ + sscop_maa_error(sop, 'I'); + KB_FREEALL(m); + + return; +} + + +/* + * USTAT PDU / SOS_IDLE Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_ustat_idle(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * Report error condition + */ + sscop_ustat_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + return; +} + + +/* + * USTAT PDU / SOS_INCONN Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_ustat_inconn(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Record error condition + */ + sscop_ustat_error(sop, m, trlr); + + /* + * Return an END to peer + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Notify user of connection failure + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + sscop_abort(sop, "stack memory\n"); + return; + } + + /* + * Go back to idle state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * USTAT PDU / SOS_READY Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_ustat_ready(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + struct ustat_pdu *up = (struct ustat_pdu *)trlr; + struct pdu_hdr *php; + sscop_seq seq1, seq2; + + NTOHL(up->ustat_nmr); + NTOHL(up->ustat_nr); + + /* + * Validate peer's current receive data sequence number + */ + if (SEQ_GT(sop->so_ack, up->ustat_nr, sop->so_ack) || + SEQ_GEQ(up->ustat_nr, sop->so_send, sop->so_ack)) { + /* + * Bad data sequence number + */ + goto goterr; + } + + /* + * Free acknowledged PDUs + */ + for (seq1 = sop->so_ack, SEQ_SET(seq2, up->ustat_nr); + SEQ_LT(seq1, seq2, sop->so_ack); + SEQ_INCR(seq1, 1)) { + sscop_pack_free(sop, seq1); + } + + /* + * Update transmit state variables + */ + sop->so_ack = seq2; + SEQ_SET(sop->so_sendmax, up->ustat_nmr); + + /* + * Get USTAT list elements + */ + SEQ_SET(seq1, ntohl(up->ustat_le1)); + SEQ_SET(seq2, ntohl(up->ustat_le2)); + + /* + * Validate elements + */ + if (SEQ_GT(sop->so_ack, seq1, sop->so_ack) || + SEQ_GEQ(seq1, seq2, sop->so_ack) || + SEQ_GEQ(seq2, sop->so_send, sop->so_ack)) { + /* + * Bad element sequence number + */ + goto goterr; + } + + /* + * Process each missing sequence number in this gap + */ + while (SEQ_LT(seq1, seq2, sop->so_ack)) { + /* + * Find corresponding SD PDU on pending ack queue + */ + php = sscop_pack_locate(sop, seq1); + if (php == NULL) { + goto goterr; + } + + /* + * Retransmit this SD PDU if it's not + * already scheduled for retranmission. + */ + if ((php->ph_rexmit_lk == NULL) && + (sop->so_rexmit_tl != php)) { + /* + * Put PDU on retransmit queue and schedule + * transmit servicing + */ + sscop_rexmit_insert(sop, php); + sop->so_flags |= SOF_XMITSRVC; + } + + /* + * Bump to next sequence number + */ + SEQ_INCR(seq1, 1); + } + + /* + * Report retransmitted PDUs + */ + sscop_maa_error(sop, 'V'); + + /* + * Free PDU buffer chain + */ + KB_FREEALL(m); + + /* + * See if transmit queues need servicing + */ + if (sop->so_flags & SOF_XMITSRVC) + sscop_service_xmit(sop); + + return; + +goterr: + /* + * Protocol/parameter error encountered + */ + sscop_maa_error(sop, 'T'); + + /* + * Free PDU buffer chain + */ + KB_FREEALL(m); + + if (sop->so_vers == SSCOP_VERS_QSAAL) + /* + * Reestablish a new connection + */ + qsaal1_reestablish(sop); + else + /* + * Initiate error recovery + */ + q2110_error_recovery(sop); + + return; +} + + +/* + * UD PDU / SOS_* Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_ud_all(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + int err; + + /* + * Pass data up to user + */ + STACK_CALL(SSCOP_UNITDATA_IND, sop->so_upper, sop->so_toku, + sop->so_connvc, (int)m, 0, err); + if (err) + KB_FREEALL(m); + return; +} + + +/* + * MD PDU / SOS_* Processor + * + * Arguments: + * sop pointer to sscop connection block + * m pointer to PDU buffer (without trailer) + * trlr pointer to PDU trailer + * + * Returns: + * none + * + */ +void +sscop_md_all(sop, m, trlr) + struct sscop *sop; + KBuffer *m; + caddr_t trlr; +{ + + /* + * We don't support MD PDUs + */ + KB_FREEALL(m); + return; +} + diff --git a/sys/netatm/uni/sscop_subr.c b/sys/netatm/uni/sscop_subr.c new file mode 100644 index 0000000..2d01229 --- /dev/null +++ b/sys/netatm/uni/sscop_subr.c @@ -0,0 +1,972 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sscop_subr.c,v 1.7 1998/08/26 23:29:19 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP - Subroutines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscop_subr.c,v 1.7 1998/08/26 23:29:19 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Local functions + */ +static int sscop_proc_xmit __P((struct sscop *)); + + +/* + * Get Next Element from STAT PDU + * + * Arguments: + * m pointer to current buffer in STAT PDU + * pelem pointer to location to store element value + * + * Returns: + * addr pointer to updated current buffer in STAT PDU + * + */ +KBuffer * +sscop_stat_getelem(m, pelem) + KBuffer *m; + sscop_seq *pelem; +{ + caddr_t cp; + + /* + * Get to start of element + * + * Note that we always ensure that the current buffer has + * at least one byte of the next element. + */ + KB_DATASTART(m, cp, caddr_t); + + /* + * See how much of element is in this buffer + */ + if (KB_LEN(m) >= sizeof(sscop_seq)) { + /* + * Get element from this buffer + */ + if ((int)cp & (sizeof(sscop_seq) - 1)) + KM_COPY(cp, (caddr_t)pelem, sizeof(sscop_seq)); + else + *pelem = *(sscop_seq *)cp; + + /* + * Update buffer controls + */ + KB_HEADADJ(m, -sizeof(sscop_seq)); + } else { + /* + * Get element split between two buffers + */ + int i, j; + + /* + * Copy what's in this buffer + */ + i = KB_LEN(m); + KM_COPY(cp, (caddr_t)pelem, i); + KB_LEN(m) = 0; + + /* + * Now get to next buffer + */ + while (m && (KB_LEN(m) == 0)) + m = KB_NEXT(m); + + /* + * And copy remainder of element + */ + j = sizeof(sscop_seq) - i; + KB_DATASTART(m, cp, caddr_t); + KM_COPY(cp, (caddr_t)pelem + i, j); + + /* + * Update buffer controls + */ + KB_HEADADJ(m, -j); + } + + /* + * Put element (sequence number) into host order + */ + NTOHL(*pelem); + + /* + * Get pointers set for next call + */ + while (m && (KB_LEN(m) == 0)) + m = KB_NEXT(m); + + return (m); +} + + +/* + * Locate SD PDU on Pending Ack Queue + * + * Arguments: + * sop pointer to sscop connection block + * seq sequence number of PDU to locate + * + * Returns: + * addr pointer to located PDU header + * 0 SD PDU sequence number not found + * + */ +struct pdu_hdr * +sscop_pack_locate(sop, seq) + struct sscop *sop; + sscop_seq seq; +{ + struct pdu_hdr *php; + + /* + * Loop thru queue until we either find the PDU or the queue's + * sequence numbers are greater than the PDU's sequence number, + * indicating that the PDU is not on the queue. + */ + for (php = sop->so_pack_hd; php; php = php->ph_pack_lk) { + if (php->ph_ns == seq) + break; + + if (SEQ_GT(php->ph_ns, seq, sop->so_ack)) { + php = NULL; + break; + } + } + + return (php); +} + + +/* + * Free Acknowledged SD PDU + * + * Arguments: + * sop pointer to sscop connection block + * seq sequence number of PDU to free + * + * Returns: + * none + * + */ +void +sscop_pack_free(sop, seq) + struct sscop *sop; + sscop_seq seq; +{ + struct pdu_hdr *php, *prev; + + /* + * Unlink PDU from pending ack queue + * + * First, check for an empty queue + */ + php = sop->so_pack_hd; + if (php == NULL) + return; + + /* + * Now check for PDU at head of queue + */ + if (php->ph_ns == seq) { + if ((sop->so_pack_hd = php->ph_pack_lk) == NULL) + sop->so_pack_tl = NULL; + goto found; + } + + /* + * Otherwise, loop thru queue until we either find the PDU or + * the queue's sequence numbers are greater than the PDU's + * sequence number, indicating that the PDU is not on the queue. + */ + prev = php; + php = php->ph_pack_lk; + while (php) { + if (php->ph_ns == seq) { + if ((prev->ph_pack_lk = php->ph_pack_lk) == NULL) + sop->so_pack_tl = prev; + goto found; + } + + if (SEQ_GT(php->ph_ns, seq, sop->so_ack)) + return; + + prev = php; + php = php->ph_pack_lk; + } + + return; + +found: + /* + * We've got the ack'ed PDU - unlink it from retransmit queue + */ + sscop_rexmit_unlink(sop, php); + + /* + * Free PDU buffers + */ + KB_FREEALL(php->ph_buf); + + return; +} + + +/* + * Insert SD PDU into Retransmit Queue + * + * Arguments: + * sop pointer to sscop connection block + * php pointer to SD PDU header + * + * Returns: + * none + * + */ +void +sscop_rexmit_insert(sop, php) + struct sscop *sop; + struct pdu_hdr *php; +{ + struct pdu_hdr *curr, *next; + sscop_seq seq = php->ph_ns; + + /* + * Check for an empty queue + */ + if ((curr = sop->so_rexmit_hd) == NULL) { + php->ph_rexmit_lk = NULL; + sop->so_rexmit_hd = php; + sop->so_rexmit_tl = php; + return; + } + + /* + * Now see if PDU belongs at head of queue + */ + if (SEQ_LT(seq, curr->ph_ns, sop->so_ack)) { + php->ph_rexmit_lk = curr; + sop->so_rexmit_hd = php; + return; + } + + /* + * Otherwise, loop thru the queue until we find the + * proper insertion point for the PDU + */ + while (next = curr->ph_rexmit_lk) { + if (SEQ_LT(seq, next->ph_ns, sop->so_ack)) { + php->ph_rexmit_lk = next; + curr->ph_rexmit_lk = php; + return; + } + curr = next; + } + + /* + * Insert PDU at end of queue + */ + php->ph_rexmit_lk = NULL; + curr->ph_rexmit_lk = php; + sop->so_rexmit_tl = php; + + return; +} + + +/* + * Unlink SD PDU from Retransmit Queue + * + * Arguments: + * sop pointer to sscop connection block + * php pointer to PDU header to unlink + * + * Returns: + * none + * + */ +void +sscop_rexmit_unlink(sop, php) + struct sscop *sop; + struct pdu_hdr *php; +{ + struct pdu_hdr *curr; + + /* + * See if PDU is on retransmit queue + */ + if ((php->ph_rexmit_lk == NULL) && (sop->so_rexmit_tl != php)) + return; + + /* + * It's here somewhere, so first check for the PDU at the + * head of the queue + */ + if (php == sop->so_rexmit_hd) { + if ((sop->so_rexmit_hd = php->ph_rexmit_lk) == NULL) + sop->so_rexmit_tl = NULL; + php->ph_rexmit_lk = NULL; + return; + } + + /* + * Otherwise, loop thru the queue until we find the PDU + */ + for (curr = sop->so_rexmit_hd; curr; curr = curr->ph_rexmit_lk) { + if (curr->ph_rexmit_lk == php) + break; + } + if (curr) { + if ((curr->ph_rexmit_lk = php->ph_rexmit_lk) == NULL) + sop->so_rexmit_tl = curr; + } else { + log(LOG_ERR, + "sscop_rexmit_unlink: Not found - sop=0x%x, php=0x%x\n", + (int)sop, (int)php); +#ifdef DIAGNOSTIC + panic("sscop_rexmit_unlink: Not found"); +#endif + } + php->ph_rexmit_lk = NULL; + + return; +} + + +/* + * Drain Transmission Queues + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +sscop_xmit_drain(sop) + struct sscop *sop; +{ + KBuffer *m; + struct pdu_hdr *php; + + /* + * Free transmission queue buffers + */ + while (m = sop->so_xmit_hd) { + sop->so_xmit_hd = KB_QNEXT(m); + KB_FREEALL(m); + } + sop->so_xmit_tl = NULL; + + /* + * Free retransmission queue + * + * All retranmission buffers are also on the pending ack + * queue (but not the converse), so we just clear the queue + * pointers here and do all the real work below. + */ + sop->so_rexmit_hd = NULL; + sop->so_rexmit_tl = NULL; + + /* + * Free pending ack queue buffers + */ + while (php = sop->so_pack_hd) { + sop->so_pack_hd = php->ph_pack_lk; + KB_FREEALL(php->ph_buf); + } + sop->so_pack_tl = NULL; + + /* + * Clear service required flag + */ + sop->so_flags &= ~SOF_XMITSRVC; + + return; +} + + +/* + * Insert SD PDU into Receive Queue + * + * Arguments: + * sop pointer to sscop connection block + * php pointer to SD PDU header + * + * Returns: + * 0 PDU successfully inserted into queue + * 1 duplicate sequence number PDU on queue, PDU not inserted + * + */ +int +sscop_recv_insert(sop, php) + struct sscop *sop; + struct pdu_hdr *php; +{ + struct pdu_hdr *curr, *next; + sscop_seq seq = php->ph_ns; + + /* + * Check for an empty queue + */ + if ((curr = sop->so_recv_hd) == NULL) { + php->ph_recv_lk = NULL; + sop->so_recv_hd = php; + sop->so_recv_tl = php; + return (0); + } + + /* + * Now see if PDU belongs at head of queue + */ + if (SEQ_LT(seq, curr->ph_ns, sop->so_rcvnext)) { + php->ph_recv_lk = curr; + sop->so_recv_hd = php; + return (0); + } + + /* + * Otherwise, loop thru the queue until we find the + * proper insertion point for the PDU. We also check + * to make sure there isn't a PDU already on the queue + * with a matching sequence number. + */ + while (next = curr->ph_recv_lk) { + if (SEQ_LT(seq, next->ph_ns, sop->so_rcvnext)) { + if (seq == curr->ph_ns) + return (1); + php->ph_recv_lk = next; + curr->ph_recv_lk = php; + return (0); + } + curr = next; + } + + /* + * Insert PDU at end of queue + */ + if (seq == curr->ph_ns) + return (1); + php->ph_recv_lk = NULL; + curr->ph_recv_lk = php; + sop->so_recv_tl = php; + + return (0); +} + + +/* + * Drain Receiver Queues + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +sscop_rcvr_drain(sop) + struct sscop *sop; +{ + struct pdu_hdr *php; + + /* + * Free receive queue buffers + */ + while (php = sop->so_recv_hd) { + sop->so_recv_hd = php->ph_recv_lk; + KB_FREEALL(php->ph_buf); + } + sop->so_recv_tl = NULL; + + return; +} + + +/* + * Service connection's transmit queues + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +sscop_service_xmit(sop) + struct sscop *sop; +{ + KBuffer *m, *n; + struct pdu_hdr *php; + int err = 0, pollsent = 0; + + /* + * Initially assume we need service + */ + sop->so_flags |= SOF_XMITSRVC; + + /* + * Loop until done with queues + * + * (Congestion control will be added later) + */ + while (1) { + if (php = sop->so_rexmit_hd) { + + /* + * Send SD PDU from retransmit queue + * + * First, get a copy of the PDU to send + */ + m = php->ph_buf; + if (KB_LEN(m) == 0) + m = KB_NEXT(m); + KB_COPY(m, 0, KB_COPYALL, n, KB_F_NOWAIT); + if (n == NULL) { + err = 1; + break; + } + + /* + * Now pass it down the stack + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, + sop->so_tokl, sop->so_connvc, (int)n, 0, err); + if (err) { + KB_FREEALL(n); + break; + } + + /* + * PDU is on its way, so remove it from + * the retransmit queue + */ + if (sop->so_rexmit_tl == php) { + sop->so_rexmit_hd = NULL; + sop->so_rexmit_tl = NULL; + } else { + sop->so_rexmit_hd = php->ph_rexmit_lk; + } + php->ph_rexmit_lk = NULL; + + /* + * Update PDU's poll sequence + */ + php->ph_nps = sop->so_pollsend; + + } else if (sop->so_xmit_hd) { + + /* + * Newly arrived data waiting to be sent. + * See if transmit window allows us to send it. + */ + if (SEQ_LT(sop->so_send, sop->so_sendmax, sop->so_ack)){ + /* + * OK, send SD PDU from transmission queue + */ + err = sscop_proc_xmit(sop); + if (err) + break; + } else { + /* + * Can't send now, so leave idle phase. + */ + if (sop->so_timer[SSCOP_T_IDLE] != 0) { + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_timer[SSCOP_T_NORESP] = + sop->so_parm.sp_timeresp; + err = 1; + } + break; + } + + } else { + + /* + * We're finished, so clear service required flag + */ + sop->so_flags &= ~SOF_XMITSRVC; + break; + } + + /* + * We've sent another SD PDU + */ + sop->so_polldata++; + + /* + * Transition into active (polling) phase + */ + if (sop->so_timer[SSCOP_T_POLL] != 0) { + if (sop->so_flags & SOF_KEEPALIVE) { + /* + * Leaving transient phase + */ + sop->so_flags &= ~SOF_KEEPALIVE; + sop->so_timer[SSCOP_T_POLL] = + sop->so_parm.sp_timepoll; + } + } else { + /* + * Leaving idle phase + */ + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_timer[SSCOP_T_NORESP] = + sop->so_parm.sp_timeresp; + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + } + + /* + * Let's see if we need to send a POLL yet + */ + if (sop->so_polldata < sop->so_parm.sp_maxpd) + continue; + + /* + * Yup, send another poll out + */ + SEQ_INCR(sop->so_pollsend, 1); + (void) sscop_send_poll(sop); + pollsent++; + + /* + * Reset data counter for this poll cycle + */ + sop->so_polldata = 0; + + /* + * Restart polling timer in active phase + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + } + + /* + * If we need/want to send a poll, but haven't sent any yet + * on this servicing, send one now + */ + if (err && (pollsent == 0)) { + /* + * Send poll + */ + SEQ_INCR(sop->so_pollsend, 1); + (void) sscop_send_poll(sop); + + /* + * Reset data counter for this poll cycle + */ + sop->so_polldata = 0; + + /* + * Restart polling timer in active phase + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + sop->so_flags &= ~SOF_KEEPALIVE; + } + + return; +} + + +/* + * Process Transmission Queue PDU + * + * For the first entry on the transmission queue: add a PDU header and + * trailer, send a copy of the PDU down the stack and move the PDU from + * the transmission queue to the pending ack queue. + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * 0 head of transmission queue successfully processed + * else processing error, tranmission queue unchanged + * + */ +static int +sscop_proc_xmit(sop) + struct sscop *sop; +{ + KBuffer *m, *ml, *n; + struct pdu_hdr *php; + sscop_seq seq; + int len = 0, err; + int pad, trlen, space; + u_char *cp; + + /* + * Get first buffer chain on queue + */ + if ((m = sop->so_xmit_hd) == NULL) + return (0); + + /* + * Count data and get to last buffer in chain + */ + for (ml = m; ; ml = KB_NEXT(ml)) { + len += KB_LEN(ml); + if (KB_NEXT(ml) == NULL) + break; + } + + /* + * Verify data length + */ + if (len > sop->so_parm.sp_maxinfo) { + sscop_abort(sop, "sscop: maximum data size exceeded\n"); + return (1); + } + + /* + * Get space for PDU header + */ + KB_HEADROOM(m, space); + if (space < sizeof(struct pdu_hdr)) { + /* + * Allocate & link buffer for header + */ + KB_ALLOC(n, sizeof(struct pdu_hdr), KB_F_NOWAIT, KB_T_HEADER); + if (n == NULL) + return (1); + + KB_LEN(n) = 0; + KB_HEADSET(n, sizeof(struct pdu_hdr)); + KB_LINKHEAD(n, m); + KB_QNEXT(n) = KB_QNEXT(m); + KB_QNEXT(m) = NULL; + sop->so_xmit_hd = n; + if (sop->so_xmit_tl == m) + sop->so_xmit_tl = n; + m = n; + } + + /* + * Figure out how much padding we'll need + */ + pad = ((len + (PDU_PAD_ALIGN - 1)) & ~(PDU_PAD_ALIGN - 1)) - len; + trlen = pad + sizeof(struct sd_pdu); + + /* + * Now get space for PDU trailer and padding + */ + KB_TAILROOM(ml, space); + if (space < trlen) { + /* + * Allocate & link buffer for pad and trailer + */ + KB_ALLOC(n, trlen, KB_F_NOWAIT, KB_T_HEADER); + if (n == NULL) + return (1); + + KB_LEN(n) = 0; + KB_LINK(n, ml); + ml = n; + } + + /* + * Build the PDU trailer + * + * Since we can't be sure of alignment in the buffers, we + * have to move this a byte at a time and we have to be + * careful with host byte order issues. + */ + KB_DATASTART(ml, cp, u_char *); + cp += KB_LEN(ml) + pad; + *cp++ = (pad << PT_PAD_SHIFT) | PT_SD; + seq = sop->so_send; + *(cp + 2) = (u_char)(seq & 0xff); + seq >>= 8; + *(cp + 1) = (u_char)(seq & 0xff); + seq >>= 8; + *(cp) = (u_char)(seq & 0xff); + KB_LEN(ml) += trlen; + + /* + * Get a copy of the SD PDU to send + */ + if (KB_LEN(m) == 0) + n = KB_NEXT(m); + else + n = m; + KB_COPY(n, 0, KB_COPYALL, n, KB_F_NOWAIT); + if (n == NULL) { + KB_LEN(ml) -= trlen; + return (1); + } + + /* + * Now pass copy down the stack + */ + STACK_CALL(CPCS_UNITDATA_INV, sop->so_lower, sop->so_tokl, + sop->so_connvc, (int)n, 0, err); + if (err) { + KB_FREEALL(n); + KB_LEN(ml) -= trlen; + return (1); + } + + /* + * PDU is on its way, so remove buffer from + * the transmission queue + */ + if (sop->so_xmit_tl == m) { + sop->so_xmit_hd = NULL; + sop->so_xmit_tl = NULL; + } else { + sop->so_xmit_hd = KB_QNEXT(m); + } + KB_QNEXT(m) = NULL; + + /* + * Build PDU header + * + * We can at least assume/require that the start of + * the user data is aligned. Also note that we don't + * include this header in the buffer len/offset fields. + */ + KB_DATASTART(m, php, struct pdu_hdr *); + php--; + php->ph_ns = sop->so_send; + php->ph_nps = sop->so_pollsend; + php->ph_buf = m; + php->ph_rexmit_lk = NULL; + php->ph_pack_lk = NULL; + + /* + * Put PDU onto the pending ack queue + */ + if (sop->so_pack_hd == NULL) + sop->so_pack_hd = php; + else + sop->so_pack_tl->ph_pack_lk = php; + sop->so_pack_tl = php; + + /* + * Finally, bump send sequence number + */ + SEQ_INCR(sop->so_send, 1); + + return (0); +} + + +/* + * Detect Retransmitted PDUs + * + * Arguments: + * sop pointer to sscop connection block + * nsq connection sequence value (N(SQ)) from received PDU + * + * Returns: + * 0 received PDU was NOT retransmitted + * 1 received PDU was retransmitted + * + */ +int +sscop_is_rexmit(sop, nsq) + struct sscop *sop; + u_char nsq; +{ + + /* + * For Q.SAAL1, N(SQ) doesn't exist + */ + if (sop->so_vers == SSCOP_VERS_QSAAL) + return (0); + + /* + * If we've already received the N(SQ) value, + * then this PDU has been retransmitted + */ + if (nsq == sop->so_rcvconn) + return (1); + + /* + * New PDU, save its N(SQ) + */ + sop->so_rcvconn = nsq; + + return (0); +} + + +/* + * Start connection poll timer + * + * Arguments: + * sop pointer to sscop connection block + * + * Returns: + * none + * + */ +void +sscop_set_poll(sop) + struct sscop *sop; +{ + + /* + * Decide which polling timer value to set + */ + if ((sop->so_xmit_hd != NULL) || SEQ_NEQ(sop->so_send, sop->so_ack)) { + /* + * Data outstanding, poll frequently + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timepoll; + sop->so_flags &= ~SOF_KEEPALIVE; + } else { + /* + * No data outstanding, just poll occassionally + */ + sop->so_timer[SSCOP_T_POLL] = sop->so_parm.sp_timekeep; + sop->so_flags |= SOF_KEEPALIVE; + } + + return; +} + diff --git a/sys/netatm/uni/sscop_timer.c b/sys/netatm/uni/sscop_timer.c new file mode 100644 index 0000000..8c23344b --- /dev/null +++ b/sys/netatm/uni/sscop_timer.c @@ -0,0 +1,576 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sscop_timer.c,v 1.6 1998/04/07 23:21:48 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP - Timer processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscop_timer.c,v 1.6 1998/04/07 23:21:48 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Local functions + */ +static void sscop_poll_expire __P((struct sscop *)); +static void sscop_noresponse_expire __P((struct sscop *)); +static void sscop_cc_expire __P((struct sscop *)); +static void sscop_idle_expire __P((struct sscop *)); + +/* + * Local variables + */ +static void (*sscop_expired[SSCOP_T_NUM]) __P((struct sscop *)) = { + sscop_poll_expire, + sscop_noresponse_expire, + sscop_cc_expire, + sscop_idle_expire +}; + + +/* + * Process an SSCOP timer tick + * + * This function is called SSCOP_HZ times a second in order to update + * all of the sscop connection timers. The sscop expiration function + * will be called to process all timer expirations. + * + * Called at splnet. + * + * Arguments: + * tip pointer to sscop timer control block + * + * Returns: + * none + * + */ +void +sscop_timeout(tip) + struct atm_time *tip; +{ + struct sscop *sop, **sprev; + int i; + + + /* + * Schedule next timeout + */ + atm_timeout(&sscop_timer, ATM_HZ/SSCOP_HZ, sscop_timeout); + + /* + * Run through all connections, updating each active timer. + * If an expired timer is found, notify that entry. + */ + sprev = &sscop_head; + while (sop = *sprev) { + + /* + * Check out each timer + */ + for (i =0; i < SSCOP_T_NUM; i++) { + + /* + * Decrement timer if it's active + */ + if (sop->so_timer[i] && (--sop->so_timer[i] == 0)) { + +#ifdef DIAGNOSTIC + { + static char *tn[] = { + "POLL", + "NORESPONSE", + "CC", + "IDLE" + }; + ATM_DEBUG3("sscop_timer: %s expired, sop=0x%x, state=%d\n", + tn[i], (int)sop, sop->so_state); + } +#endif + + /* + * Expired timer - process it + */ + (*sscop_expired[i])(sop); + + /* + * Make sure connection still exists + */ + if (*sprev != sop) + break; + } + } + + /* + * Update previous pointer if current control + * block wasn't deleted + */ + if (*sprev == sop) + sprev = &sop->so_next; + } +} + + +/* + * Process an SSCOP Timer_POLL expiration + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * none + * + */ +static void +sscop_poll_expire(sop) + struct sscop *sop; +{ + + /* + * Validate current state + */ + if ((sop->so_state != SOS_READY) && + ((sop->so_state != SOS_INRESYN) || + (sop->so_vers != SSCOP_VERS_QSAAL))) { + log(LOG_ERR, "sscop: invalid %s state: sop=0x%x, state=%d\n", + "Timer_POLL", (int)sop, sop->so_state); + return; + } + + /* + * Send next poll along its way + */ + SEQ_INCR(sop->so_pollsend, 1); + (void) sscop_send_poll(sop); + + /* + * Reset data counter for this poll cycle + */ + sop->so_polldata = 0; + + /* + * Reset polling timer + */ + sscop_set_poll(sop); + + return; +} + + +/* + * Process an SSCOP Timer_IDLE expiration + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * none + * + */ +static void +sscop_idle_expire(sop) + struct sscop *sop; +{ + + /* + * Timer_IDLE only valid in READY state + */ + if (sop->so_state != SOS_READY) { + log(LOG_ERR, "sscop: invalid %s state: sop=0x%x, state=%d\n", + "Timer_IDLE", (int)sop, sop->so_state); + return; + } + + /* + * Send next poll along its way + */ + SEQ_INCR(sop->so_pollsend, 1); + (void) sscop_send_poll(sop); + + /* + * Reset data counter for this poll cycle + */ + sop->so_polldata = 0; + + /* + * Start NO-RESPONSE timer + */ + sop->so_timer[SSCOP_T_NORESP] = sop->so_parm.sp_timeresp; + + /* + * Reset polling timer + */ + sscop_set_poll(sop); + + return; +} + + +/* + * Process an SSCOP Timer_NORESPONSE expiration + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * none + * + */ +static void +sscop_noresponse_expire(sop) + struct sscop *sop; +{ + int err; + + /* + * Validate current state + */ + if ((sop->so_state != SOS_READY) && + ((sop->so_state != SOS_INRESYN) || + (sop->so_vers != SSCOP_VERS_QSAAL))) { + log(LOG_ERR, "sscop: invalid %s state: sop=0x%x, state=%d\n", + "Timer_NORESPONSE", (int)sop, sop->so_state); + return; + } + + /* + * Peer seems to be dead, so terminate session + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, + sop->so_toku, sop->so_connvc, + SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + /* + * Error, force retry + */ + sop->so_timer[SSCOP_T_NORESP] = 1; + return; + } + + /* + * Stop data transfer timers + */ + sop->so_timer[SSCOP_T_POLL] = 0; + sop->so_timer[SSCOP_T_IDLE] = 0; + sop->so_flags &= ~SOF_KEEPALIVE; + + /* + * Notify peer of termination + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Report peer's failure + */ + sscop_maa_error(sop, 'P'); + + if (sop->so_vers == SSCOP_VERS_QSAAL) + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + else + /* + * Clear out appropriate queues + */ + q2110_prep_retrieve(sop); + + /* + * Return to IDLE state + */ + sop->so_state = SOS_IDLE; + + return; +} + + +/* + * Process an SSCOP Timer_CC expiration + * + * Arguments: + * sop pointer to sscop connection control block + * + * Returns: + * none + * + */ +static void +sscop_cc_expire(sop) + struct sscop *sop; +{ + int err; + + /* + * Process timeout based on protocol state + */ + switch (sop->so_state) { + + case SOS_OUTCONN: + /* + * No response to our BGN yet + */ + if (sop->so_connctl < sop->so_parm.sp_maxcc) { + + /* + * Send another BGN PDU + */ + sop->so_connctl++; + (void) sscop_send_bgn(sop, SSCOP_SOURCE_USER); + + /* + * Restart retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + } else { + + /* + * Retransmit limit exceeded, terminate session + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, + sop->so_toku, sop->so_connvc, + SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + /* + * Error, force retry + */ + sop->so_timer[SSCOP_T_CC] = 1; + break; + } + + /* + * Notify peer of termination + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Report establishment failure + */ + sscop_maa_error(sop, 'O'); + + /* + * Clear reestablishment flag + */ + sop->so_flags &= ~SOF_REESTAB; + + /* + * Return to IDLE state + */ + sop->so_state = SOS_IDLE; + } + break; + + case SOS_OUTDISC: + /* + * No response to our END yet + */ + if (sop->so_connctl < sop->so_parm.sp_maxcc) { + + /* + * Send another END PDU + */ + sop->so_connctl++; + (void) sscop_send_end(sop, SSCOP_SOURCE_LAST); + + /* + * Restart retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + } else { + + /* + * Retransmit limit exceeded, force session termination + */ + STACK_CALL(SSCOP_RELEASE_CNF, sop->so_upper, + sop->so_toku, sop->so_connvc, 0, 0, err); + if (err) { + /* + * Error, force retry + */ + sop->so_timer[SSCOP_T_CC] = 1; + break; + } + + /* + * Report establishment failure + */ + sscop_maa_error(sop, 'O'); + + /* + * Return to IDLE state + */ + sop->so_state = SOS_IDLE; + } + break; + + case SOS_OUTRESYN: +rexmitrs: + /* + * No response to our RS yet + */ + if (sop->so_connctl < sop->so_parm.sp_maxcc) { + + /* + * Send another RS PDU + */ + sop->so_connctl++; + (void) sscop_send_rs(sop); + + /* + * Restart retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + } else { + + /* + * Retransmit limit exceeded, terminate session + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, + sop->so_toku, sop->so_connvc, + SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + /* + * Error, force retry + */ + sop->so_timer[SSCOP_T_CC] = 1; + break; + } + + /* + * Notify peer of termination + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Report establishment failure + */ + sscop_maa_error(sop, 'O'); + + if (sop->so_vers == SSCOP_VERS_QSAAL) + /* + * Clear connection data + */ + qsaal1_clear_connection(sop); + + /* + * Return to IDLE state + */ + sop->so_state = SOS_IDLE; + } + break; + + case SOS_CONRESYN: /* Q.SAAL1 */ +#if (SOS_OUTRECOV != SOS_CONRESYN) + case SOS_OUTRECOV: /* Q.2110 */ +#endif + if (sop->so_vers == SSCOP_VERS_QSAAL) { + /* + * Handle timeout for SOS_CONRESYN + */ + goto rexmitrs; + } + + /* + * Handle timeout for SOS_OUTRECOV + */ + + /* + * No response to our ER yet + */ + if (sop->so_connctl < sop->so_parm.sp_maxcc) { + + /* + * Send another ER PDU + */ + sop->so_connctl++; + (void) sscop_send_er(sop); + + /* + * Restart retransmit timer + */ + sop->so_timer[SSCOP_T_CC] = sop->so_parm.sp_timecc; + + } else { + + /* + * Retransmit limit exceeded, terminate session + */ + STACK_CALL(SSCOP_RELEASE_IND, sop->so_upper, + sop->so_toku, sop->so_connvc, + SSCOP_UU_NULL, SSCOP_SOURCE_SSCOP, err); + if (err) { + /* + * Error, force retry + */ + sop->so_timer[SSCOP_T_CC] = 1; + break; + } + + /* + * Notify peer of termination + */ + (void) sscop_send_end(sop, SSCOP_SOURCE_SSCOP); + + /* + * Report establishment failure + */ + sscop_maa_error(sop, 'O'); + + /* + * Clear receiver buffer + */ + sscop_rcvr_drain(sop); + + /* + * Return to IDLE state + */ + sop->so_state = SOS_IDLE; + } + break; + + default: + log(LOG_ERR, "sscop: invalid %s state: sop=0x%x, state=%d\n", + "Timer_CC", (int)sop, sop->so_state); + } +} + diff --git a/sys/netatm/uni/sscop_upper.c b/sys/netatm/uni/sscop_upper.c new file mode 100644 index 0000000..be9556d --- /dev/null +++ b/sys/netatm/uni/sscop_upper.c @@ -0,0 +1,412 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sscop_upper.c,v 1.6 1998/08/26 23:29:20 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP - CPCS SAP interface processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: sscop_upper.c,v 1.6 1998/08/26 23:29:20 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/sscop.h> +#include <netatm/uni/sscop_misc.h> +#include <netatm/uni/sscop_pdu.h> +#include <netatm/uni/sscop_var.h> + + +/* + * Local functions + */ +static caddr_t sscop_pdu_receive __P((KBuffer *, struct sscop *, int *)); + + +/* + * Local variables + */ +static union { + struct bgn_pdu t_bgn; + struct bgak_pdu t_bgak; + struct end_pdu t_end; + struct endak_q2110_pdu t_endak_q2110; + struct endak_qsaal_pdu t_endak_qsaal; + struct rs_pdu t_rs; + struct rsak_q2110_pdu t_rsak_q2110; + struct rsak_qsaal_pdu t_rsak_qsaal; + struct bgrej_pdu t_bgrej; + struct sd_pdu t_sd; + struct sdp_pdu t_sdp; + struct er_pdu t_er; + struct poll_pdu t_poll; + struct stat_pdu t_stat; + struct ustat_pdu t_ustat; + struct ud_pdu t_ud; + struct md_pdu t_md; + struct erak_pdu t_erak; +} sscop_trailer; + + +/* + * PDU length validation table + */ +struct pdulen { + int min; + int max; +}; + +static struct pdulen qsaal_pdulen[] = { + {0, 0}, + {sizeof(struct bgn_pdu), sizeof(struct bgn_pdu)}, + {sizeof(struct bgak_pdu), sizeof(struct bgak_pdu)}, + {sizeof(struct end_pdu), sizeof(struct end_pdu)}, + {sizeof(struct endak_qsaal_pdu),sizeof(struct endak_qsaal_pdu)}, + {sizeof(struct rs_pdu), sizeof(struct rs_pdu)}, + {sizeof(struct rsak_qsaal_pdu), sizeof(struct rsak_qsaal_pdu)}, + {sizeof(struct bgrej_pdu), sizeof(struct bgrej_pdu)}, + {sizeof(struct sd_pdu), sizeof(struct sd_pdu) + PDU_MAX_INFO}, + {sizeof(struct sdp_pdu), sizeof(struct sdp_pdu) + PDU_MAX_INFO}, + {sizeof(struct poll_pdu), sizeof(struct poll_pdu)}, + {sizeof(struct stat_pdu), sizeof(struct stat_pdu) + PDU_MAX_STAT}, + {sizeof(struct ustat_pdu), sizeof(struct ustat_pdu)}, + {sizeof(struct ud_pdu), sizeof(struct ud_pdu) + PDU_MAX_INFO}, + {sizeof(struct md_pdu), sizeof(struct md_pdu) + PDU_MAX_INFO}, + {0, 0} +}; + +static struct pdulen q2110_pdulen[] = { + {0, 0}, + {sizeof(struct bgn_pdu), sizeof(struct bgn_pdu) + PDU_MAX_UU}, + {sizeof(struct bgak_pdu), sizeof(struct bgak_pdu) + PDU_MAX_UU}, + {sizeof(struct end_pdu), sizeof(struct end_pdu) + PDU_MAX_UU}, + {sizeof(struct endak_q2110_pdu),sizeof(struct endak_q2110_pdu)}, + {sizeof(struct rs_pdu), sizeof(struct rs_pdu) + PDU_MAX_UU}, + {sizeof(struct rsak_q2110_pdu), sizeof(struct rsak_q2110_pdu)}, + {sizeof(struct bgrej_pdu), sizeof(struct bgrej_pdu) + PDU_MAX_UU}, + {sizeof(struct sd_pdu), sizeof(struct sd_pdu) + PDU_MAX_INFO}, + {sizeof(struct er_pdu), sizeof(struct er_pdu)}, + {sizeof(struct poll_pdu), sizeof(struct poll_pdu)}, + {sizeof(struct stat_pdu), sizeof(struct stat_pdu) + PDU_MAX_STAT}, + {sizeof(struct ustat_pdu), sizeof(struct ustat_pdu)}, + {sizeof(struct ud_pdu), sizeof(struct ud_pdu) + PDU_MAX_INFO}, + {sizeof(struct md_pdu), sizeof(struct md_pdu) + PDU_MAX_INFO}, + {sizeof(struct erak_pdu), sizeof(struct erak_pdu)} +}; + + +/* + * PDUs with Pad Length Fields + */ +static u_char qsaal_padlen[] = { + 0, /* --- */ + 0, /* BGN */ + 0, /* BGAK */ + 0, /* END */ + 0, /* ENDAK */ + 0, /* RS */ + 0, /* RSAK */ + 0, /* BGREJ */ + 1, /* SD */ + 1, /* SDP */ + 0, /* POLL */ + 0, /* STAT */ + 0, /* USTAT */ + 1, /* UD */ + 1, /* MD */ + 0 /* --- */ +}; + +static u_char q2110_padlen[] = { + 0, /* --- */ + 1, /* BGN */ + 1, /* BGAK */ + 1, /* END */ + 0, /* ENDAK */ + 1, /* RS */ + 0, /* RSAK */ + 1, /* BGREJ */ + 1, /* SD */ + 0, /* ER */ + 0, /* POLL */ + 0, /* STAT */ + 0, /* USTAT */ + 1, /* UD */ + 1, /* MD */ + 0 /* ERAK */ +}; + + +/* + * SSCOP Upper Stack Command Handler + * + * This function will receive all of the stack commands issued from the + * layer below SSCOP (ie. CPCS). Currently, only incoming PDUs will be + * received here. The appropriate processing function will be determined + * based on the received PDU type and the current sscop control block state. + * + * Arguments: + * cmd stack command code + * tok session token + * arg1 command specific argument + * arg2 command specific argument + * + * Returns: + * none + * + */ +void +sscop_upper(cmd, tok, arg1, arg2) + int cmd; + void *tok; + int arg1; + int arg2; +{ + struct sscop *sop = (struct sscop *)tok; + void (**ptab) __P((struct sscop *, KBuffer *, caddr_t)); + void (*func) __P((struct sscop *, KBuffer *, caddr_t)); + caddr_t trlr; + int type; + + ATM_DEBUG5("sscop_upper: cmd=0x%x, sop=0x%x, state=%d, arg1=0x%x, arg2=0x%x\n", + cmd, (int)sop, sop->so_state, arg1, arg2); + + switch (cmd) { + + case CPCS_UNITDATA_SIG: + /* + * Decode/validate received PDU + */ + trlr = sscop_pdu_receive((KBuffer *)arg1, sop, &type); + if (trlr == NULL) { + return; + } + + /* + * Validate sscop state + */ + if (sop->so_state > SOS_MAXSTATE) { + log(LOG_ERR, + "sscop_upper: invalid state sop=0x%x, state=%d\n", + (int)sop, sop->so_state); + KB_FREEALL((KBuffer *)arg1); + return; + } + + /* + * Call event processing function + */ + ptab = sop->so_vers == SSCOP_VERS_QSAAL ? + sscop_qsaal_pdutab[type]: + sscop_q2110_pdutab[type]; + func = ptab[sop->so_state]; + if (func == NULL) { + log(LOG_ERR, + "sscop_upper: unsupported pdu=%d, state=%d\n", + type, sop->so_state); + break; + } + (*func)(sop, (KBuffer *)arg1, trlr); + break; + + default: + log(LOG_ERR, "sscop_upper: unknown cmd 0x%x, sop=0x%x\n", + cmd, (int)sop); + } + + return; +} + + +/* + * Decode and Validate Received PDU + * + * This function will process all received SSCOP PDUs. The PDU type will be + * determined and PDU format validation will be performed. If the PDU is + * successfully decoded and validated, the buffer chain will have the PDU + * trailer removed, but any resultant zero-length buffers will NOT be freed. + * If the PDU fails validation, then the buffer chain will be freed. + * + * Arguments: + * m pointer to PDU buffer chain + * sop pointer to sscop connection block + * typep address to store PDU type + * + * Returns: + * addr pointer to (contiguous) PDU trailer + * 0 invalid PDU, buffer chain freed + * + */ +static caddr_t +sscop_pdu_receive(m, sop, typep) + KBuffer *m; + struct sscop *sop; + int *typep; +{ + KBuffer *m0, *ml, *mn; + caddr_t cp, tp; + int len, tlen, type, plen; + + /* + * Calculate PDU length and find the last two buffers in the chain + */ + len = 0; + for (m0 = m, ml = mn = NULL; m0; m0 = KB_NEXT(m0)) { + len += KB_LEN(m0); + mn = ml; + ml = m0; + } + + /* + * Make sure we've got a minimum sized PDU + */ + if (len < PDU_MIN_LEN) + goto badpdu; + + /* + * Get PDU type field + */ + if (KB_LEN(ml) >= PDU_MIN_LEN) { + KB_DATAEND(ml, tp, caddr_t); + tp -= PDU_MIN_LEN; + } else { + KB_DATAEND(mn, tp, caddr_t); + tp -= (PDU_MIN_LEN - KB_LEN(ml)); + } + *typep = type = *tp & PT_TYPE_MASK; + + /* + * Check up on PDU length + */ + if (sop->so_vers == SSCOP_VERS_QSAAL) { + if ((len < (tlen = qsaal_pdulen[type].min)) || + (len > qsaal_pdulen[type].max) || + (len & PDU_LEN_MASK)) + goto badpdu; + } else { + if ((len < (tlen = q2110_pdulen[type].min)) || + (len > q2110_pdulen[type].max) || + (len & PDU_LEN_MASK)) + goto badpdu; + } + + /* + * Get a contiguous, aligned PDU trailer and adjust buffer + * controls to remove trailer + */ + if (KB_LEN(ml) >= tlen) { + /* + * Trailer is contained in last buffer + */ + KB_TAILADJ(ml, -tlen); + KB_DATAEND(ml, cp, caddr_t); + if ((int)cp & PDU_ADDR_MASK) { + /* + * Trailer not aligned in buffer, use local memory + */ + KM_COPY(cp, (caddr_t)&sscop_trailer, tlen); + cp = (caddr_t)&sscop_trailer; + } + } else { + /* + * Trailer is split across buffers, use local memory + */ + caddr_t cp1; + int off = tlen - KB_LEN(ml); + + cp = (caddr_t)&sscop_trailer; + + /* + * Ensure trailer is within last two buffers + */ + if ((mn == NULL) || (KB_LEN(mn) < off)) + goto badpdu; + + KB_DATASTART(ml, cp1, caddr_t); + KM_COPY(cp1, cp + off, KB_LEN(ml)); + KB_LEN(ml) = 0; + KB_TAILADJ(mn, -off); + KB_DATAEND(mn, cp1, caddr_t); + KM_COPY(cp1, cp, off); + } + + /* + * Get possible PDU Pad Length + */ + if (sop->so_vers == SSCOP_VERS_QSAAL) { + if (qsaal_padlen[type]) + plen = (*tp & PT_PAD_MASK) >> PT_PAD_SHIFT; + else + plen = 0; + } else { + if (q2110_padlen[type]) + plen = (*tp & PT_PAD_MASK) >> PT_PAD_SHIFT; + else + plen = 0; + } + + /* + * Perform Pad Length adjustments + */ + if (plen) { + if (KB_LEN(ml) >= plen) { + /* + * All pad bytes in last buffer + */ + KB_TAILADJ(ml, -plen); + } else { + /* + * Pad bytes split between buffers + */ + plen -= KB_LEN(ml); + if ((mn == NULL) || (KB_LEN(mn) < plen)) + goto badpdu; + KB_LEN(ml) = 0; + KB_TAILADJ(mn, -plen); + } + } + + return (cp); + +badpdu: + /* + * This MAA Error is only supposed to be for a PDU length violation, + * but we use it for any PDU format error. + */ + sscop_maa_error(sop, 'U'); + sscop_pdu_print(sop, m, "badpdu received"); + KB_FREEALL(m); + return (NULL); +} + diff --git a/sys/netatm/uni/sscop_var.h b/sys/netatm/uni/sscop_var.h new file mode 100644 index 0000000..9a739d3 --- /dev/null +++ b/sys/netatm/uni/sscop_var.h @@ -0,0 +1,283 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: sscop_var.h,v 1.6 1998/04/07 23:21:57 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * SSCOP protocol control blocks + * + */ + +#ifndef _UNI_SSCOP_VAR_H +#define _UNI_SSCOP_VAR_H + +/* + * Structure containing information for each SSCOP connection. + */ +struct sscop { + struct sscop *so_next; /* Next connection in chain */ + u_char so_state; /* Connection state (see below) */ + u_short so_flags; /* Connection flags (see below) */ + enum sscop_vers so_vers; /* SSCOP version */ + + /* Transmitter variables */ + sscop_seq so_send; /* VT(S) - next SD to send */ + sscop_seq so_sendmax; /* VT(MS) - max SD to send + 1 */ + sscop_seq so_ack; /* VT(A) - next expected ack */ + sscop_seq so_pollsend; /* VT(PS) - last POLL sent */ + sscop_seq so_pollack; /* VT(PA) - next expected STAT */ + short so_polldata; /* VT(PD) - SD's sent between POLLs */ + short so_connctl; /* VT(CC) - un-ack'd BGN,END,ER,RS */ + u_char so_sendconn; /* VT(SQ) - last BGN,ER,RS sent */ + + /* Receiver variables */ + sscop_seq so_rcvnext; /* VR(R) - next SD to receive */ + sscop_seq so_rcvhigh; /* VR(H) - next highest SD to receive */ + sscop_seq so_rcvmax; /* VR(MR) - max SD to receive + 1 */ + u_char so_rcvconn; /* VR(SQ) - last BGN,ER,RS received */ + + /* PDU queues */ + KBuffer *so_xmit_hd; /* SD transmission queue head */ + KBuffer *so_xmit_tl; /* SD transmission queue tail */ + struct pdu_hdr *so_rexmit_hd; /* SD retransmission queue head */ + struct pdu_hdr *so_rexmit_tl; /* SD retransmission queue head */ + struct pdu_hdr *so_pack_hd; /* SD pending ack queue head */ + struct pdu_hdr *so_pack_tl; /* SD pending ack queue tail */ + struct pdu_hdr *so_recv_hd; /* SD receive queue head */ + struct pdu_hdr *so_recv_tl; /* SD receive queue tail */ + + /* Connection parameters */ + struct sscop_parms so_parm; /* Connection parameters */ + + /* Timers */ + u_short so_timer[SSCOP_T_NUM]; /* Connection timers */ + + /* Stack variables */ + Atm_connvc *so_connvc; /* Connection vcc for this stack */ + void *so_toku; /* Stack upper layer's token */ + void *so_tokl; /* Stack lower layer's token */ + void (*so_upper) /* Stack upper layer's interface */ + __P((int, void *, int, int)); + void (*so_lower) /* Stack lower layer's interface */ + __P((int, void *, int, int)); + u_short so_headout; /* Output buffer headroom */ +}; + +/* + * Connection States + * + * Notes: + * # - state valid only for Q.SAAL1 + * ## - state valid only for Q.2110 + */ +#define SOS_INST 0 /* Instantiated, waiting for INIT */ +#define SOS_IDLE 1 /* Idle connection */ +#define SOS_OUTCONN 2 /* Outgoing connection pending */ +#define SOS_INCONN 3 /* Incoming connection pending */ +#define SOS_OUTDISC 4 /* Outgoing disconnection pending */ +#define SOS_OUTRESYN 5 /* Outgoing resynchronization pending */ +#define SOS_INRESYN 6 /* Incoming resynchronization pending */ +#define SOS_CONRESYN 7 /* Concurrent resynch pending (#) */ +#define SOS_OUTRECOV 7 /* Outgoing recovery pending (##) */ +#define SOS_RECOVRSP 8 /* Recovery response pending (##) */ +#define SOS_INRECOV 9 /* Incoming recovery pending (##) */ +#define SOS_READY 10 /* Data transfer ready */ +#define SOS_TERM 11 /* Waiting for TERM */ + +#define SOS_MAXSTATE 11 /* Maximum state value */ +#define SOS_NUMSTATES (SOS_MAXSTATE+1)/* Number of states */ + +/* + * Connection Flags + */ +#define SOF_NOCLRBUF 0x0001 /* Clear buffers = no */ +#define SOF_REESTAB 0x0002 /* SSCOP initiated reestablishment */ +#define SOF_XMITSRVC 0x0004 /* Transmit queues need servicing */ +#define SOF_KEEPALIVE 0x0008 /* Polling in transient phase */ +#define SOF_ENDSSCOP 0x0010 /* Last END PDU, SOURCE=SSCOP */ +#define SOF_NOCREDIT 0x0020 /* Transmit window closed */ + + +/* + * SSCOP statistics + */ +struct sscop_stat { + u_long sos_connects; /* Connection instances */ + u_long sos_aborts; /* Connection aborts */ + u_long sos_maa_error[MAA_ERROR_COUNT]; /* Management errors */ +}; + +#ifdef ATM_KERNEL +/* + * Global function declarations + */ + /* sscop.c */ +int sscop_start __P((void)); +int sscop_stop __P((void)); +void sscop_maa_error __P((struct sscop *, int)); +void sscop_abort __P((struct sscop *, char *)); + + /* sscop_lower.c */ +void sscop_lower __P((int, void *, int, int)); +void sscop_aa_noop_0 __P((struct sscop *, int, int)); +void sscop_aa_noop_1 __P((struct sscop *, int, int)); +void sscop_init_inst __P((struct sscop *, int, int)); +void sscop_term_all __P((struct sscop *, int, int)); + + /* sscop_pdu.c */ +int sscop_send_bgn __P((struct sscop *, int)); +int sscop_send_bgak __P((struct sscop *)); +int sscop_send_bgrej __P((struct sscop *)); +int sscop_send_end __P((struct sscop *, int)); +int sscop_send_endak __P((struct sscop *)); +int sscop_send_rs __P((struct sscop *)); +int sscop_send_rsak __P((struct sscop *)); +int sscop_send_er __P((struct sscop *)); +int sscop_send_erak __P((struct sscop *)); +int sscop_send_poll __P((struct sscop *)); +int sscop_send_stat __P((struct sscop *, sscop_seq)); +int sscop_send_ustat __P((struct sscop *, sscop_seq)); +int sscop_send_ud __P((struct sscop *, KBuffer *)); +void sscop_pdu_print __P((struct sscop *, KBuffer *, char *)); + + /* sscop_sigaa.c */ +void sscop_estreq_idle __P((struct sscop *, int, int)); +void sscop_estrsp_inconn __P((struct sscop *, int, int)); +void sscop_relreq_outconn __P((struct sscop *, int, int)); +void sscop_relreq_inconn __P((struct sscop *, int, int)); +void sscop_relreq_ready __P((struct sscop *, int, int)); +void sscop_datreq_ready __P((struct sscop *, int, int)); +void sscop_udtreq_all __P((struct sscop *, int, int)); + + /* sscop_sigcpcs.c */ +void sscop_noop __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgn_idle __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgn_outdisc __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgn_outresyn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgn_inresyn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgak_error __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgak_idle __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgak_outconn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgrej_error __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgrej_outconn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgrej_inconn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgrej_outresyn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_bgrej_ready __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_end_idle __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_end_inconn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_end_outdisc __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_endak_error __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_endak_inconn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_endak_outdisc __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_endak_ready __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_rs_error __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_rs_idle __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_rsak_error __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_rsak_idle __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_rsak_outresyn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_sd_error __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_sd_idle __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_sd_inconn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_poll_error __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_poll_idle __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_poll_inconn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_stat_error __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_stat_idle __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_stat_inconn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_stat_ready __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_ustat_error __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_ustat_idle __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_ustat_inconn __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_ustat_ready __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_ud_all __P((struct sscop *, KBuffer *, caddr_t)); +void sscop_md_all __P((struct sscop *, KBuffer *, caddr_t)); + + /* sscop_subr.c */ +KBuffer * sscop_stat_getelem __P((KBuffer *, sscop_seq *)); +struct pdu_hdr *sscop_pack_locate __P((struct sscop *, sscop_seq)); +void sscop_pack_free __P((struct sscop *, sscop_seq)); +void sscop_rexmit_insert __P((struct sscop *, struct pdu_hdr *)); +void sscop_rexmit_unlink __P((struct sscop *, struct pdu_hdr *)); +void sscop_xmit_drain __P((struct sscop *)); +int sscop_recv_insert __P((struct sscop *, struct pdu_hdr *)); +void sscop_rcvr_drain __P((struct sscop *)); +void sscop_service_xmit __P((struct sscop *)); +int sscop_is_rexmit __P((struct sscop *, u_char)); +void sscop_set_poll __P((struct sscop *)); + + /* sscop_timer.c */ +void sscop_timeout __P((struct atm_time *)); + + /* sscop_upper.c */ +void sscop_upper __P((int, void *, int, int)); + + /* q2110_sigaa.c */ + + /* q2110_sigcpcs.c */ + + /* q2110_subr.c */ +void q2110_clear_xmit __P((struct sscop *)); +void q2110_init_state __P((struct sscop *)); +void q2110_prep_retrieve __P((struct sscop *)); +void q2110_prep_recovery __P((struct sscop *)); +void q2110_deliver_data __P((struct sscop *)); +void q2110_error_recovery __P((struct sscop *)); + + /* qsaal1_sigaa.c */ + + /* qsaal1_sigcpcs.c */ + + /* qsaal1_subr.c */ +void qsaal1_reestablish __P((struct sscop *)); +void qsaal1_reset_xmit __P((struct sscop *)); +void qsaal1_reset_rcvr __P((struct sscop *)); +void qsaal1_clear_connection __P((struct sscop *)); + + +/* + * External variables + */ +extern struct sp_info sscop_pool; +extern int sscop_vccnt; +extern struct sscop *sscop_head; +extern struct sscop_stat sscop_stat; +extern struct atm_time sscop_timer; +extern void (*(*sscop_qsaal_aatab[])) + __P((struct sscop *, int, int)); +extern void (*(*sscop_q2110_aatab[])) + __P((struct sscop *, int, int)); +extern void (*(*sscop_qsaal_pdutab[])) + __P((struct sscop *, KBuffer *, caddr_t)); +extern void (*(*sscop_q2110_pdutab[])) + __P((struct sscop *, KBuffer *, caddr_t)); + +#endif /* ATM_KERNEL */ + +#endif /* _UNI_SSCOP_VAR_H */ diff --git a/sys/netatm/uni/uni.h b/sys/netatm/uni/uni.h new file mode 100644 index 0000000..700e859 --- /dev/null +++ b/sys/netatm/uni/uni.h @@ -0,0 +1,50 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: uni.h,v 1.2 1997/05/06 22:20:39 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * Protocol definitions + * + */ + +#ifndef _UNI_UNI_H +#define _UNI_UNI_H + +/* + * UNI Version + */ +enum uni_vers { + UNI_VERS_3_0, + UNI_VERS_3_1, + UNI_VERS_4_0 +}; + +#endif /* _UNI_UNI_H */ diff --git a/sys/netatm/uni/uni_load.c b/sys/netatm/uni/uni_load.c new file mode 100644 index 0000000..23e7ff5 --- /dev/null +++ b/sys/netatm/uni/uni_load.c @@ -0,0 +1,450 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: uni_load.c,v 1.6 1997/05/06 22:20:43 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * Loadable kernel module support + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: uni_load.c,v 1.6 1997/05/06 22:20:43 mks Exp $"; +#endif + +#ifndef ATM_UNI_MODULE +#include "opt_atm.h" +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> + +/* + * External functions + */ +int sscop_start __P((void)); +int sscop_stop __P((void)); +int sscf_uni_start __P((void)); +int sscf_uni_stop __P((void)); +int uniip_start __P((void)); +int uniip_stop __P((void)); +int unisig_start __P((void)); +int unisig_stop __P((void)); + +/* + * Local functions + */ +static int uni_start __P((void)); +static int uni_stop __P((void)); + + +/* + * Initialize uni processing + * + * This will be called during module loading. We just notify all of our + * sub-services to initialize. + * + * Arguments: + * none + * + * Returns: + * 0 startup was successful + * errno startup failed - reason indicated + * + */ +static int +uni_start() +{ + int err; + + /* + * Verify software version + */ + if (atm_version != ATM_VERSION) { + log(LOG_ERR, "version mismatch: uni=%d.%d kernel=%d.%d\n", + ATM_VERS_MAJ(ATM_VERSION), ATM_VERS_MIN(ATM_VERSION), + ATM_VERS_MAJ(atm_version), ATM_VERS_MIN(atm_version)); + return (EINVAL); + } + + /* + * Initialize uni sub-services + */ + err = sscop_start(); + if (err) + goto done; + + err = sscf_uni_start(); + if (err) + goto done; + + err = unisig_start(); + if (err) + goto done; + + err = uniip_start(); + if (err) + goto done; + +done: + return (err); +} + + +/* + * Halt uni processing + * + * This will be called just prior to unloading the module from + * memory. All sub-services will be notified of the termination. + * + * Arguments: + * none + * + * Returns: + * 0 shutdown was successful + * errno shutdown failed - reason indicated + * + */ +static int +uni_stop() +{ + int err, s = splnet(); + + /* + * Terminate uni sub-services + */ + err = uniip_stop(); + if (err) + goto done; + + err = unisig_stop(); + if (err) + goto done; + + err = sscf_uni_stop(); + if (err) + goto done; + + err = sscop_stop(); + if (err) + goto done; + +done: + (void) splx(s); + return (err); +} + + +#ifdef ATM_UNI_MODULE +/* + ******************************************************************* + * + * Loadable Module Support + * + ******************************************************************* + */ +static int uni_doload __P((void)); +static int uni_dounload __P((void)); + +/* + * Generic module load processing + * + * This function is called by an OS-specific function when this + * module is being loaded. + * + * Arguments: + * none + * + * Returns: + * 0 load was successful + * errno load failed - reason indicated + * + */ +static int +uni_doload() +{ + int err = 0; + + /* + * Start us up + */ + err = uni_start(); + if (err) + /* Problems, clean up */ + (void)uni_stop(); + + return (err); +} + + +/* + * Generic module unload processing + * + * This function is called by an OS-specific function when this + * module is being unloaded. + * + * Arguments: + * none + * + * Returns: + * 0 unload was successful + * errno unload failed - reason indicated + * + */ +static int +uni_dounload() +{ + int err = 0; + + /* + * OK, try to clean up our mess + */ + err = uni_stop(); + + return (err); +} + + +#ifdef sun +/* + * Loadable driver description + */ +struct vdldrv uni_drv = { + VDMAGIC_PSEUDO, /* Pseudo Driver */ + "uni_mod", /* name */ + NULL, /* dev_ops */ + NULL, /* bdevsw */ + NULL, /* cdevsw */ + 0, /* blockmajor */ + 0 /* charmajor */ +}; + + +/* + * Loadable module support entry point + * + * This is the routine called by the vd driver for all loadable module + * functions for this pseudo driver. This routine name must be specified + * on the modload(1) command. This routine will be called whenever the + * modload(1), modunload(1) or modstat(1) commands are issued for this + * module. + * + * Arguments: + * cmd vd command code + * vdp pointer to vd driver's structure + * vdi pointer to command-specific vdioctl_* structure + * vds pointer to status structure (VDSTAT only) + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +int +uni_mod(cmd, vdp, vdi, vds) + int cmd; + struct vddrv *vdp; + caddr_t vdi; + struct vdstat *vds; +{ + int err = 0; + + switch (cmd) { + + case VDLOAD: + /* + * Module Load + * + * We dont support any user configuration + */ + err = uni_doload(); + if (err == 0) + /* Let vd driver know about us */ + vdp->vdd_vdtab = (struct vdlinkage *)&uni_drv; + break; + + case VDUNLOAD: + /* + * Module Unload + */ + err = uni_dounload(); + break; + + case VDSTAT: + /* + * Module Status + */ + + /* Not much to say at the moment */ + + break; + + default: + log(LOG_ERR, "uni_mod: Unknown vd command 0x%x\n", cmd); + err = EINVAL; + } + + return (err); +} +#endif /* sun */ + +#ifdef __FreeBSD__ + +#include <sys/exec.h> +#include <sys/sysent.h> +#include <sys/lkm.h> + +/* + * Loadable miscellaneous module description + */ +MOD_MISC(uni); + + +/* + * Loadable module support "load" entry point + * + * This is the routine called by the lkm driver whenever the + * modload(1) command is issued for this module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +static int +uni_load(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + return(uni_doload()); +} + + +/* + * Loadable module support "unload" entry point + * + * This is the routine called by the lkm driver whenever the + * modunload(1) command is issued for this module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +static int +uni_unload(lkmtp, cmd) + struct lkm_table *lkmtp; + int cmd; +{ + return(uni_dounload()); +} + + +/* + * Loadable module support entry point + * + * This is the routine called by the lkm driver for all loadable module + * functions for this driver. This routine name must be specified + * on the modload(1) command. This routine will be called whenever the + * modload(1), modunload(1) or modstat(1) commands are issued for this + * module. + * + * Arguments: + * lkmtp pointer to lkm drivers's structure + * cmd lkm command code + * ver lkm version + * + * Returns: + * 0 command was successful + * errno command failed - reason indicated + * + */ +int +uni_mod(lkmtp, cmd, ver) + struct lkm_table *lkmtp; + int cmd; + int ver; +{ + MOD_DISPATCH(uni, lkmtp, cmd, ver, + uni_load, uni_unload, lkm_nullcmd); +} +#endif /* __FreeBSD__ */ + +#else /* !ATM_UNI_MODULE */ + +/* + ******************************************************************* + * + * Kernel Compiled Module Support + * + ******************************************************************* + */ +static void uni_doload __P((void *)); + +SYSINIT(atmuni, SI_SUB_PROTO_END, SI_ORDER_ANY, uni_doload, NULL) + +/* + * Kernel initialization + * + * Arguments: + * arg Not used + * + * Returns: + * none + * + */ +static void +uni_doload(void *arg) +{ + int err = 0; + + /* + * Start us up + */ + err = uni_start(); + if (err) { + /* Problems, clean up */ + (void)uni_stop(); + + log(LOG_ERR, "ATM UNI unable to initialize (%d)!!\n", err); + } + return; +} +#endif /* ATM_UNI_MODULE */ + diff --git a/sys/netatm/uni/uniarp.c b/sys/netatm/uni/uniarp.c new file mode 100644 index 0000000..f316a73 --- /dev/null +++ b/sys/netatm/uni/uniarp.c @@ -0,0 +1,1231 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: uniarp.c,v 1.10 1998/07/20 18:58:45 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * UNI ATMARP support (RFC1577) + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: uniarp.c,v 1.10 1998/07/20 18:58:45 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/uniip_var.h> + + +/* + * Global variables + */ +struct uniarp *uniarp_arptab[UNIARP_HASHSIZ] = {NULL}; +struct uniarp *uniarp_nomaptab = NULL; +struct uniarp *uniarp_pvctab = NULL; +struct atm_time uniarp_timer = {0, 0}; /* Aging timer */ +struct uniarp_stat uniarp_stat = {0}; +int uniarp_print = 0; + +Atm_endpoint uniarp_endpt = { + NULL, + ENDPT_ATMARP, + uniarp_ioctl, + uniarp_getname, + uniarp_connected, + uniarp_cleared, + NULL, + NULL, + NULL, + NULL, + uniarp_cpcs_data, + NULL, + NULL, + NULL, + NULL +}; + +struct sp_info uniarp_pool = { + "uni arp pool", /* si_name */ + sizeof(struct uniarp), /* si_blksiz */ + 10, /* si_blkcnt */ + 200 /* si_maxallow */ +}; + + +/* + * Local variables + */ +static void uniarp_server_mode __P((struct uniip *)); +static void uniarp_client_mode __P((struct uniip *, Atm_addr *)); + + +/* + * Process module loading notification + * + * Called whenever the uni module is initializing. + * + * Arguments: + * none + * + * Returns: + * 0 initialization successful + * errno initialization failed - reason indicated + * + */ +int +uniarp_start() +{ + int err; + + /* + * Register our endpoint + */ + err = atm_endpoint_register(&uniarp_endpt); + + return (err); +} + + +/* + * Process module unloading notification + * + * Called whenever the uni module is about to be unloaded. All signalling + * instances will have been previously detached. All uniarp resources + * must be freed now. + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +uniarp_stop() +{ + int i; + + /* + * Make sure the arp table is empty + */ + for (i = 0; i < UNIARP_HASHSIZ; i++) { + if (uniarp_arptab[i] != NULL) + panic("uniarp_stop: arp table not empty"); + } + + /* + * Cancel timers + */ + (void) atm_untimeout(&uniarp_timer); + + /* + * De-register ourselves + */ + (void) atm_endpoint_deregister(&uniarp_endpt); + + /* + * Free our storage pools + */ + atm_release_pool(&uniarp_pool); +} + + +/* + * Process IP Network Interface Activation + * + * Called whenever an IP network interface becomes active. + * + * Called at splnet. + * + * Arguments: + * uip pointer to UNI IP interface + * + * Returns: + * none + * + */ +void +uniarp_ipact(uip) + struct uniip *uip; +{ + struct unisig *usp; + + ATM_DEBUG1("uniarp_ipact: uip=0x%x\n", (int)uip); + + /* + * Set initial state + */ + uip->uip_arpstate = UIAS_NOTCONF; + uip->uip_arpsvratm.address_format = T_ATM_ABSENT; + uip->uip_arpsvratm.address_length = 0; + uip->uip_arpsvrsub.address_format = T_ATM_ABSENT; + uip->uip_arpsvrsub.address_length = 0; + + usp = (struct unisig *)uip->uip_ipnif->inf_nif->nif_pif->pif_siginst; + if (usp->us_addr.address_format != T_ATM_ABSENT) + uip->uip_flags |= UIF_IFADDR; + + /* + * Make sure aging timer is running + */ + if ((uniarp_timer.ti_flag & TIF_QUEUED) == 0) + atm_timeout(&uniarp_timer, UNIARP_AGING, uniarp_aging); + + return; +} + + +/* + * Process IP Network Interface Deactivation + * + * Called whenever an IP network interface becomes inactive. All VCCs + * for this interface should already have been closed. + * + * Called at splnet. + * + * Arguments: + * uip pointer to UNI IP interface + * + * Returns: + * none + * + */ +void +uniarp_ipdact(uip) + struct uniip *uip; +{ + struct ip_nif *inp = uip->uip_ipnif; + struct uniarp *uap, *unext; + int i; + + ATM_DEBUG1("uniarp_ipdact: uip=0x%x\n", (int)uip); + + /* + * Delete all interface entries + */ + for (i = 0; i < UNIARP_HASHSIZ; i++) { + for (uap = uniarp_arptab[i]; uap; uap = unext) { + unext = uap->ua_next; + + if (uap->ua_intf != uip) + continue; + + /* + * All VCCs should (better) be gone by now + */ + if (uap->ua_ivp) + panic("uniarp_ipdact: entry not empty"); + + /* + * Clean up any loose ends + */ + UNIARP_CANCEL(uap); + + /* + * Delete entry from arp table and free entry + */ + UNIARP_DELETE(uap); + atm_free((caddr_t)uap); + } + } + + /* + * Clean up 'nomap' table + */ + for (uap = uniarp_nomaptab; uap; uap = unext) { + unext = uap->ua_next; + + if (uap->ua_intf != uip) + continue; + + /* + * All VCCs should (better) be gone by now + */ + if (uap->ua_ivp) + panic("uniarp_ipdact: entry not empty"); + + /* + * Clean up any loose ends + */ + UNIARP_CANCEL(uap); + + /* + * Delete entry from 'no map' table and free entry + */ + UNLINK(uap, struct uniarp, uniarp_nomaptab, ua_next); + atm_free((caddr_t)uap); + } + + /* + * Also clean up pvc table + */ + for (uap = uniarp_pvctab; uap; uap = unext) { + unext = uap->ua_next; + + if (uap->ua_intf != uip) + continue; + + /* + * All PVCs should (better) be gone by now + */ + panic("uniarp_ipdact: pvc table not empty"); + } + + /* + * Cancel arp interface timer + */ + UNIIP_ARP_CANCEL(uip); + + /* + * Stop aging timer if this is the last active interface + */ + if (uniip_head == uip && uip->uip_next == NULL) + (void) atm_untimeout(&uniarp_timer); +} + + +/* + * Process Interface ATM Address Change + * + * This function is called whenever the ATM address for a physical + * interface is set/changed. + * + * Called at splnet. + * + * Arguments: + * sip pointer to interface's UNI signalling instance + * + * Returns: + * none + * + */ +void +uniarp_ifaddr(sip) + struct siginst *sip; +{ + struct atm_nif *nip; + struct uniip *uip; + + ATM_DEBUG1("uniarp_ifaddr: sip=0x%x\n", (int)sip); + + /* + * We've got to handle this for every network interface + */ + for (nip = sip->si_pif->pif_nif; nip; nip = nip->nif_pnext) { + + /* + * Find our control blocks + */ + for (uip = uniip_head; uip; uip = uip->uip_next) { + if (uip->uip_ipnif->inf_nif == nip) + break; + } + if (uip == NULL) + continue; + + /* + * We don't support changing prefix (yet) + */ + if (uip->uip_flags & UIF_IFADDR) { + log(LOG_ERR, "uniarp_ifaddr: change not supported\n"); + continue; + } + + /* + * Note that address has been set and figure out what + * to do next + */ + uip->uip_flags |= UIF_IFADDR; + + if (uip->uip_arpstate == UIAS_CLIENT_PADDR) { + /* + * This is what we're waiting for + */ + uniarp_client_mode(uip, NULL); + } + } + + return; +} + + +/* + * Set ATMARP Server Mode + * + * This function is called to configure the local node to become the + * ATMARP server for the specified LIS. + * + * Called at splnet. + * + * Arguments: + * uip pointer to UNI IP interface + * + * Returns: + * none + * + */ +static void +uniarp_server_mode(uip) + struct uniip *uip; +{ + struct ip_nif *inp; + struct atm_nif *nip; + struct siginst *sgp; + struct ipvcc *ivp, *inext; + struct uniarp *uap, *unext; + int i; + + ATM_DEBUG1("uniarp_server_mode: uip=0x%x\n", (int)uip); + + /* + * Handle client/server mode changes first + */ + switch (uip->uip_arpstate) { + + case UIAS_NOTCONF: + case UIAS_SERVER_ACTIVE: + case UIAS_CLIENT_PADDR: + /* + * Nothing to undo + */ + break; + + case UIAS_CLIENT_POPEN: + /* + * We're becoming the server, so kill the pending connection + */ + UNIIP_ARP_CANCEL(uip); + if (ivp = uip->uip_arpsvrvcc) { + ivp->iv_flags &= ~IVF_NOIDLE; + uip->uip_arpsvrvcc = NULL; + (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED); + } + break; + + case UIAS_CLIENT_REGISTER: + case UIAS_CLIENT_ACTIVE: + /* + * We're becoming the server, but leave existing VCC as a + * "normal" IP VCC + */ + UNIIP_ARP_CANCEL(uip); + ivp = uip->uip_arpsvrvcc; + ivp->iv_flags &= ~IVF_NOIDLE; + uip->uip_arpsvrvcc = NULL; + break; + } + + /* + * Revalidate status for all arp entries on this interface + */ + for (i = 0; i < UNIARP_HASHSIZ; i++) { + for (uap = uniarp_arptab[i]; uap; uap = unext) { + unext = uap->ua_next; + + if (uap->ua_intf != uip) + continue; + + if (uap->ua_origin >= UAO_PERM) + continue; + + if (uap->ua_origin >= UAO_SCSP) { + if (uniarp_validate_ip(uip, &uap->ua_dstip, + uap->ua_origin) == 0) + continue; + } + + if (uap->ua_ivp == NULL) { + UNIARP_CANCEL(uap); + UNIARP_DELETE(uap); + atm_free((caddr_t)uap); + continue; + } + + if (uap->ua_flags & UAF_VALID) { + uap->ua_flags |= UAF_LOCKED; + for (ivp = uap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*ivp->iv_ipnif->inf_arpnotify) + (ivp, MAP_INVALID); + } + uap->ua_flags &= ~(UAF_LOCKED | UAF_VALID); + } + uap->ua_aging = 1; + uap->ua_origin = 0; + } + } + + /* + * OK, now let's make ourselves the server + */ + inp = uip->uip_ipnif; + nip = inp->inf_nif; + sgp = nip->nif_pif->pif_siginst; + ATM_ADDR_SEL_COPY(&sgp->si_addr, nip->nif_sel, &uip->uip_arpsvratm); + uip->uip_arpsvrip = IA_SIN(inp->inf_addr)->sin_addr; + uip->uip_arpstate = UIAS_SERVER_ACTIVE; + return; +} + + +/* + * Set ATMARP Client Mode + * + * This function is called to configure the local node to be an ATMARP + * client on the specified LIS using the specified ATMARP server. + * + * Called at splnet. + * + * Arguments: + * uip pointer to UNI IP interface + * aap pointer to the ATMARP server's ATM address + * + * Returns: + * none + * + */ +static void +uniarp_client_mode(uip, aap) + struct uniip *uip; + Atm_addr *aap; +{ + struct ip_nif *inp = uip->uip_ipnif; + struct uniarp *uap, *unext; + struct ipvcc *ivp, *inext; + int i; + + ATM_DEBUG2("uniarp_client_mode: uip=0x%x, atm=(%s,-)\n", + (int)uip, aap ? unisig_addr_print(aap): "-"); + + /* + * Handle client/server mode changes first + */ + switch (uip->uip_arpstate) { + + case UIAS_NOTCONF: + case UIAS_CLIENT_PADDR: + /* + * Nothing to undo + */ + break; + + case UIAS_CLIENT_POPEN: + /* + * If this is this a timeout retry, just go do it + */ + if (aap == NULL) + break; + + /* + * If this isn't really a different arpserver, we're done + */ + if (ATM_ADDR_EQUAL(aap, &uip->uip_arpsvratm)) + return; + + /* + * We're changing servers, so kill the pending connection + */ + UNIIP_ARP_CANCEL(uip); + if (ivp = uip->uip_arpsvrvcc) { + ivp->iv_flags &= ~IVF_NOIDLE; + uip->uip_arpsvrvcc = NULL; + (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED); + } + break; + + case UIAS_CLIENT_REGISTER: + case UIAS_CLIENT_ACTIVE: + /* + * If this isn't really a different arpserver, we're done + */ + if (ATM_ADDR_EQUAL(aap, &uip->uip_arpsvratm)) + return; + + /* + * We're changing servers, but leave existing VCC as a + * "normal" IP VCC + */ + UNIIP_ARP_CANCEL(uip); + ivp = uip->uip_arpsvrvcc; + ivp->iv_flags &= ~IVF_NOIDLE; + uip->uip_arpsvrvcc = NULL; + break; + + case UIAS_SERVER_ACTIVE: + /* + * We're changing from server mode, so... + * + * Reset valid/authoritative status for all arp entries + * on this interface + */ + for (i = 0; i < UNIARP_HASHSIZ; i++) { + for (uap = uniarp_arptab[i]; uap; uap = unext) { + unext = uap->ua_next; + + if (uap->ua_intf != uip) + continue; + + if (uap->ua_origin >= UAO_PERM) + continue; + + if (uap->ua_ivp == NULL) { + UNIARP_CANCEL(uap); + UNIARP_DELETE(uap); + atm_free((caddr_t)uap); + continue; + } + + if (uap->ua_flags & UAF_VALID) { + uap->ua_flags |= UAF_LOCKED; + for (ivp = uap->ua_ivp; ivp; + ivp = inext) { + inext = ivp->iv_arpnext; + (*ivp->iv_ipnif->inf_arpnotify) + (ivp, MAP_INVALID); + } + uap->ua_flags &= + ~(UAF_LOCKED | UAF_VALID); + } + uap->ua_aging = 1; + uap->ua_origin = 0; + } + } + uip->uip_arpsvratm.address_format = T_ATM_ABSENT; + uip->uip_arpsvratm.address_length = 0; + uip->uip_arpsvrsub.address_format = T_ATM_ABSENT; + uip->uip_arpsvrsub.address_length = 0; + uip->uip_arpsvrip.s_addr = 0; + break; + } + + /* + * Save the arp server address, if supplied now + */ + if (aap) + ATM_ADDR_COPY(aap, &uip->uip_arpsvratm); + + /* + * If the interface's ATM address isn't set yet, then we + * can't do much until it is + */ + if ((uip->uip_flags & UIF_IFADDR) == 0) { + uip->uip_arpstate = UIAS_CLIENT_PADDR; + return; + } + + /* + * Just to keep things simple, if we already have (or are trying to + * setup) any SVCs to our new server, kill the connections so we can + * open a "fresh" SVC for the arpserver connection. + */ + for (i = 0; i < UNIARP_HASHSIZ; i++) { + for (uap = uniarp_arptab[i]; uap; uap = unext) { + unext = uap->ua_next; + + if (ATM_ADDR_EQUAL(&uip->uip_arpsvratm, + &uap->ua_dstatm) && + ATM_ADDR_EQUAL(&uip->uip_arpsvrsub, + &uap->ua_dstatmsub)) { + uap->ua_flags &= ~UAF_VALID; + for (ivp = uap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*inp->inf_arpnotify)(ivp, MAP_FAILED); + } + } + } + } + for (uap = uniarp_nomaptab; uap; uap = unext) { + unext = uap->ua_next; + + if (ATM_ADDR_EQUAL(&uip->uip_arpsvratm, &uap->ua_dstatm) && + ATM_ADDR_EQUAL(&uip->uip_arpsvrsub, &uap->ua_dstatmsub)) { + uap->ua_flags &= ~UAF_VALID; + for (ivp = uap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*inp->inf_arpnotify)(ivp, MAP_FAILED); + } + } + } + + /* + * Now, get an arp entry for the server connection + */ + uip->uip_arpstate = UIAS_CLIENT_POPEN; + uap = (struct uniarp *)atm_allocate(&uniarp_pool); + if (uap == NULL) { + UNIIP_ARP_TIMER(uip, 1 * ATM_HZ); + return; + } + + /* + * Next, initiate an SVC to the server + */ + if ((*inp->inf_createsvc)(&inp->inf_nif->nif_if, AF_ATM, + (caddr_t)&uip->uip_arpsvratm, &ivp)) { + atm_free((caddr_t)uap); + UNIIP_ARP_TIMER(uip, 1 * ATM_HZ); + return; + } + + /* + * Finally, get everything set up and wait for the SVC + * connection to complete + */ + uip->uip_arpsvrvcc = ivp; + ivp->iv_flags |= IVF_NOIDLE; + + ATM_ADDR_COPY(&uip->uip_arpsvratm, &uap->ua_dstatm); + ATM_ADDR_COPY(&uip->uip_arpsvrsub, &uap->ua_dstatmsub); + uap->ua_intf = uip; + + LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)uap; + + LINK2TAIL(uap, struct uniarp, uniarp_nomaptab, ua_next); + + return; +} + + +/* + * Process a UNI ARP interface timeout + * + * Called when a previously scheduled uniip arp interface timer expires. + * Processing will be based on the current uniip arp state. + * + * Called at splnet. + * + * Arguments: + * tip pointer to uniip arp timer control block + * + * Returns: + * none + * + */ +void +uniarp_iftimeout(tip) + struct atm_time *tip; +{ + struct ip_nif *inp; + struct uniip *uip; + + + /* + * Back-off to uniip control block + */ + uip = (struct uniip *) + ((caddr_t)tip - (int)(&((struct uniip *)0)->uip_arptime)); + + ATM_DEBUG2("uniarp_iftimeout: uip=0x%x, state=%d\n", (int)uip, + uip->uip_arpstate); + + /* + * Process timeout based on protocol state + */ + switch (uip->uip_arpstate) { + + case UIAS_CLIENT_POPEN: + /* + * Retry opening arp server connection + */ + uniarp_client_mode(uip, NULL); + break; + + case UIAS_CLIENT_REGISTER: + /* + * Resend registration request + */ + inp = uip->uip_ipnif; + (void) uniarp_arp_req(uip, &(IA_SIN(inp->inf_addr)->sin_addr)); + + /* + * Restart timer + */ + UNIIP_ARP_TIMER(uip, 2 * ATM_HZ); + + break; + + case UIAS_CLIENT_ACTIVE: + /* + * Refresh our registration + */ + inp = uip->uip_ipnif; + (void) uniarp_arp_req(uip, &(IA_SIN(inp->inf_addr)->sin_addr)); + + /* + * Restart timer + */ + UNIIP_ARP_TIMER(uip, UNIARP_REGIS_RETRY); + + break; + + default: + log(LOG_ERR, "uniarp_iftimeout: invalid state %d\n", + uip->uip_arpstate); + } +} + + +/* + * UNI ARP IOCTL support + * + * Function will be called at splnet. + * + * Arguments: + * code PF_ATM sub-operation code + * data pointer to code specific parameter data area + * arg1 pointer to code specific argument + * + * Returns: + * 0 request procesed + * errno error processing request - reason indicated + * + */ +int +uniarp_ioctl(code, data, arg1) + int code; + caddr_t data; + caddr_t arg1; +{ + struct atmaddreq *aap; + struct atmdelreq *adp; + struct atmsetreq *asp; + struct atminfreq *aip; + struct air_arp_rsp aar; + struct air_asrv_rsp asr; + struct atm_pif *pip; + struct atm_nif *nip; + struct ipvcc *ivp, *inext; + struct uniip *uip; + struct uniarp *uap; + struct unisig *usp; + struct in_addr ip; + Atm_addr atmsub; + u_long dst; + int err = 0, i, buf_len; + caddr_t buf_addr; + + switch (code) { + + case AIOCS_ADD_ARP: + /* + * Add a permanent ARP mapping + */ + aap = (struct atmaddreq *)data; + uip = (struct uniip *)arg1; + if (aap->aar_arp_addr.address_format != T_ATM_ENDSYS_ADDR) { + err = EINVAL; + break; + } + atmsub.address_format = T_ATM_ABSENT; + atmsub.address_length = 0; + ip = SATOSIN(&aap->aar_arp_dst)->sin_addr; + + /* + * Validate IP address + */ + if (uniarp_validate_ip(uip, &ip, aap->aar_arp_origin) != 0) { + err = EADDRNOTAVAIL; + break; + } + + /* + * Add an entry to the cache + */ + err = uniarp_cache_svc(uip, &ip, &aap->aar_arp_addr, + &atmsub, aap->aar_arp_origin); + break; + + case AIOCS_DEL_ARP: + /* + * Delete an ARP mapping + */ + adp = (struct atmdelreq *)data; + uip = (struct uniip *)arg1; + ip = SATOSIN(&adp->adr_arp_dst)->sin_addr; + + /* + * Now find the entry to be deleted + */ + UNIARP_LOOKUP(ip.s_addr, uap); + if (uap == NULL) { + err = ENOENT; + break; + } + + /* + * Notify all VCCs using this entry that they must finish + * up now. + */ + uap->ua_flags |= UAF_LOCKED; + for (ivp = uap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_FAILED); + } + + /* + * Now free up the entry + */ + UNIARP_CANCEL(uap); + UNIARP_DELETE(uap); + atm_free((caddr_t)uap); + break; + + case AIOCS_SET_ASV: + /* + * Set interface ARP server address + */ + asp = (struct atmsetreq *)data; + for (uip = uniip_head; uip; uip = uip->uip_next) { + if (uip->uip_ipnif->inf_nif == (struct atm_nif *)arg1) + break; + } + if (uip == NULL) { + err = ENOPROTOOPT; + break; + } + + /* + * Check for our own address + */ + usp = (struct unisig *) + uip->uip_ipnif->inf_nif->nif_pif->pif_siginst; + if (ATM_ADDR_EQUAL(&asp->asr_arp_addr, &usp->us_addr)) { + asp->asr_arp_addr.address_format = T_ATM_ABSENT; + } + + /* + * If we're going into server mode, make sure we can get + * the memory for the prefix list before continuing + */ + if (asp->asr_arp_addr.address_format == T_ATM_ABSENT) { + i = asp->asr_arp_plen / sizeof(struct uniarp_prf); + if (i <= 0) { + err = EINVAL; + break; + } + buf_len = i * sizeof(struct uniarp_prf); + buf_addr = KM_ALLOC(buf_len, M_DEVBUF, M_NOWAIT); + if (buf_addr == NULL) { + err = ENOMEM; + break; + } + err = copyin(asp->asr_arp_pbuf, buf_addr, buf_len); + if (err) { + KM_FREE(buf_addr, buf_len, M_DEVBUF); + break; + } + } else { + /* Silence the compiler */ + i = 0; + buf_addr = NULL; + } + + /* + * Free any existing prefix address list + */ + if (uip->uip_prefix != NULL) { + KM_FREE(uip->uip_prefix, + uip->uip_nprefix * sizeof(struct uniarp_prf), + M_DEVBUF); + uip->uip_prefix = NULL; + uip->uip_nprefix = 0; + } + + if (asp->asr_arp_addr.address_format == T_ATM_ABSENT) { + /* + * Set ATMARP server mode + */ + uip->uip_prefix = (struct uniarp_prf *)buf_addr; + uip->uip_nprefix = i; + uniarp_server_mode(uip); + } else + /* + * Set ATMARP client mode + */ + uniarp_client_mode(uip, &asp->asr_arp_addr); + break; + + case AIOCS_INF_ARP: + /* + * Get ARP table information + */ + aip = (struct atminfreq *)data; + + if (aip->air_arp_addr.sa_family != AF_INET) + break; + dst = SATOSIN(&aip->air_arp_addr)->sin_addr.s_addr; + + buf_addr = aip->air_buf_addr; + buf_len = aip->air_buf_len; + + pip = ((struct siginst *)arg1)->si_pif; + + /* + * Run through entire arp table + */ + for (i = 0; i < UNIARP_HASHSIZ; i++) { + for (uap = uniarp_arptab[i]; uap; uap = uap->ua_next) { + /* + * We only want valid entries learned + * from the supplied interface. + */ + nip = uap->ua_intf->uip_ipnif->inf_nif; + if (nip->nif_pif != pip) + continue; + if ((dst != INADDR_ANY) && + (dst != uap->ua_dstip.s_addr)) + continue; + + /* + * Make sure there's room in the user's buffer + */ + if (buf_len < sizeof(aar)) { + err = ENOSPC; + break; + } + + /* + * Fill in info to be returned + */ + SATOSIN(&aar.aap_arp_addr)->sin_family = + AF_INET; + SATOSIN(&aar.aap_arp_addr)->sin_addr.s_addr = + uap->ua_dstip.s_addr; + (void) sprintf(aar.aap_intf, "%s%d", + nip->nif_if.if_name, + nip->nif_if.if_unit); + aar.aap_flags = uap->ua_flags; + aar.aap_origin = uap->ua_origin; + if (uap->ua_flags & UAF_VALID) + aar.aap_age = uap->ua_aging + + uap->ua_retry * UNIARP_RETRY_AGE; + else + aar.aap_age = 0; + ATM_ADDR_COPY(&uap->ua_dstatm, &aar.aap_addr); + ATM_ADDR_COPY(&uap->ua_dstatmsub, + &aar.aap_subaddr); + + /* + * Copy the response into the user's buffer + */ + if (err = copyout((caddr_t)&aar, buf_addr, + sizeof(aar))) + break; + buf_addr += sizeof(aar); + buf_len -= sizeof(aar); + } + if (err) + break; + } + + /* + * Now go through the 'nomap' table + */ + if (err || (dst != INADDR_ANY)) + goto updbuf; + for (uap = uniarp_nomaptab; uap; uap = uap->ua_next) { + /* + * We only want valid entries learned + * from the supplied interface. + */ + nip = uap->ua_intf->uip_ipnif->inf_nif; + if (nip->nif_pif != pip) + continue; + + /* + * Make sure there's room in the user's buffer + */ + if (buf_len < sizeof(aar)) { + err = ENOSPC; + break; + } + + /* + * Fill in info to be returned + */ + SATOSIN(&aar.aap_arp_addr)->sin_family = AF_INET; + SATOSIN(&aar.aap_arp_addr)->sin_addr.s_addr = 0; + (void) sprintf(aar.aap_intf, "%s%d", + nip->nif_if.if_name, nip->nif_if.if_unit); + aar.aap_flags = 0; + aar.aap_origin = uap->ua_origin; + aar.aap_age = 0; + ATM_ADDR_COPY(&uap->ua_dstatm, &aar.aap_addr); + ATM_ADDR_COPY(&uap->ua_dstatmsub, + &aar.aap_subaddr); + + /* + * Copy the response into the user's buffer + */ + if (err = copyout((caddr_t)&aar, buf_addr, + sizeof(aar))) + break; + buf_addr += sizeof(aar); + buf_len -= sizeof(aar); + } + +updbuf: + /* + * Update the buffer pointer and length + */ + aip->air_buf_addr = buf_addr; + aip->air_buf_len = buf_len; + + /* + * If the user wants the refresh status reset and no + * errors have been encountered, then do the reset + */ + if ((err == 0) && (aip->air_arp_flags & ARP_RESET_REF)) { + for (i = 0; i < UNIARP_HASHSIZ; i++) { + for (uap = uniarp_arptab[i]; uap; + uap = uap->ua_next) { + /* + * We only want valid entries learned + * from the supplied interface. + */ + nip = uap->ua_intf->uip_ipnif->inf_nif; + if (nip->nif_pif != pip) + continue; + if ((dst != INADDR_ANY) && + (dst != uap->ua_dstip.s_addr)) + continue; + + /* + * Reset refresh flag + */ + uap->ua_flags &= ~UAF_REFRESH; + } + } + } + break; + + case AIOCS_INF_ASV: + /* + * Get ARP server information + */ + aip = (struct atminfreq *)data; + + buf_addr = aip->air_buf_addr; + buf_len = aip->air_buf_len; + + for (uip = uniip_head; uip; uip = uip->uip_next) { + + if ((arg1 != NULL) && + (uip->uip_ipnif->inf_nif != (struct atm_nif *)arg1)) + continue; + + /* + * Make sure there's room in the user's buffer + */ + if (buf_len < sizeof(asr)) { + err = ENOSPC; + break; + } + + /* + * Fill in info to be returned + */ + nip = uip->uip_ipnif->inf_nif; + (void) sprintf(asr.asp_intf, "%s%d", + nip->nif_if.if_name, nip->nif_if.if_unit); + asr.asp_state = uip->uip_arpstate; + if (uip->uip_arpstate == UIAS_SERVER_ACTIVE) { + asr.asp_addr.address_format = T_ATM_ABSENT; + asr.asp_addr.address_length = 0; + } else { + ATM_ADDR_COPY(&uip->uip_arpsvratm, + &asr.asp_addr); + } + asr.asp_subaddr.address_format = T_ATM_ABSENT; + asr.asp_subaddr.address_length = 0; + asr.asp_nprefix = uip->uip_nprefix; + + /* + * Copy the response into the user's buffer + */ + if (err = copyout((caddr_t)&asr, buf_addr, sizeof(asr))) + break; + buf_addr += sizeof(asr); + buf_len -= sizeof(asr); + + /* + * Copy the prefix list into the user's buffer + */ + if (uip->uip_nprefix) { + i = uip->uip_nprefix + * sizeof(struct uniarp_prf); + if (buf_len < i) { + err = ENOSPC; + break; + } + if (err = copyout(uip->uip_prefix, buf_addr, i)) + break; + buf_addr += i; + buf_len -= i; + } + } + + /* + * Update the buffer pointer and length + */ + aip->air_buf_addr = buf_addr; + aip->air_buf_len = buf_len; + break; + + default: + err = EOPNOTSUPP; + } + + return (err); +} + + +/* + * Get Connection's Application/Owner Name + * + * Arguments: + * tok uniarp connection token (pointer to ipvcc) + * + * Returns: + * addr pointer to string containing our name + * + */ +caddr_t +uniarp_getname(tok) + void *tok; +{ + return ("ATMARP"); +} + diff --git a/sys/netatm/uni/uniarp_cache.c b/sys/netatm/uni/uniarp_cache.c new file mode 100644 index 0000000..6c9537e --- /dev/null +++ b/sys/netatm/uni/uniarp_cache.c @@ -0,0 +1,420 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: uniarp_cache.c,v 1.8 1998/08/26 23:29:20 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * UNI ATMARP support (RFC1577) - ARP cache processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: uniarp_cache.c,v 1.8 1998/08/26 23:29:20 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/uniip_var.h> + + +/* + * Add data to the arp table cache + * + * Called at splnet. + * + * Arguments: + * uip pointer to UNI IP interface + * ip pointer to IP address structure + * atm pointer to ATM address structure + * atmsub pointer to ATM subaddress structure + * origin source of arp information + * + * Returns: + * 0 cache successfully updated + * else updated failed - reason indicated + * + */ +int +uniarp_cache_svc(uip, ip, atm, atmsub, origin) + struct uniip *uip; + struct in_addr *ip; + Atm_addr *atm; + Atm_addr *atmsub; + u_int origin; +{ + struct ip_nif *inp; + struct ipvcc *ivp, *inext, *itail; + struct uniarp *nouap, *ipuap; + char abuf[64]; + +#ifdef DIAGNOSTIC + strncpy(abuf, unisig_addr_print(atmsub), sizeof(abuf)); + ATM_DEBUG4("cache_svc: ip=%s, atm=(%s,%s), origin=%d\n", + inet_ntoa(*ip), unisig_addr_print(atm), abuf, origin); +#endif + + /* + * Get interface info + */ + inp = uip->uip_ipnif; + + /* + * Find both cached entry and 'nomap' entries for this data. + */ + UNIARP_LOOKUP(ip->s_addr, ipuap); + for (nouap = uniarp_nomaptab; nouap; nouap = nouap->ua_next) { + if (ATM_ADDR_EQUAL(atm, &nouap->ua_dstatm) && + ATM_ADDR_EQUAL(atmsub, &nouap->ua_dstatmsub) && + (nouap->ua_intf == uip)) + break; + } + + /* + * If there aren't any entries yet, create one + */ + if ((ipuap == NULL) && (nouap == NULL)) { + ipuap = (struct uniarp *)atm_allocate(&uniarp_pool); + if (ipuap == NULL) + return (ENOMEM); + ipuap->ua_dstip.s_addr = ip->s_addr; + ipuap->ua_dstatm.address_format = T_ATM_ABSENT; + ipuap->ua_dstatmsub.address_format = T_ATM_ABSENT; + ipuap->ua_intf = uip; + UNIARP_ADD(ipuap); + } + + /* + * If there's no cached mapping, then make the 'nomap' entry + * the new cached entry. + */ + if (ipuap == NULL) { + UNLINK(nouap, struct uniarp, uniarp_nomaptab, ua_next); + nouap->ua_dstip.s_addr = ip->s_addr; + ipuap = nouap; + nouap = NULL; + UNIARP_ADD(ipuap); + } + + /* + * We need to check the consistency of the new data with any + * cached data. So taking the easy case first, if there isn't + * an ATM address in the cache then we can skip all these checks. + */ + if (ipuap->ua_dstatm.address_format != T_ATM_ABSENT) { + /* + * See if the new data conflicts with what's in the cache + */ + if (ATM_ADDR_EQUAL(atm, &ipuap->ua_dstatm) && + ATM_ADDR_EQUAL(atmsub, &ipuap->ua_dstatmsub) && + (uip == ipuap->ua_intf)) { + /* + * No conflicts here + */ + goto dataok; + } + + /* + * Data conflict...how we deal with this depends on + * the origins of the conflicting data + */ + if (origin == ipuap->ua_origin) { + /* + * The new data has equal precedence - if there are + * any VCCs using this entry, then we reject this + * "duplicate IP address" update. + */ + if (ipuap->ua_ivp != NULL) { + strncpy(abuf, unisig_addr_print(atmsub), + sizeof(abuf)); + log(LOG_WARNING, + "uniarp: duplicate IP address %s from %s,%s\n", + inet_ntoa(*ip), unisig_addr_print(atm), + abuf); + return (EACCES); + } + + } else if (origin > ipuap->ua_origin) { + /* + * New data's origin has higher precedence, + * so accept the new mapping and notify IP/ATM + * that a mapping change has occurred. IP/ATM will + * close any VCC's which aren't waiting for this map. + */ + ipuap->ua_flags |= UAF_LOCKED; + for (ivp = ipuap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*inp->inf_arpnotify)(ivp, MAP_CHANGED); + } + ipuap->ua_flags &= ~UAF_LOCKED; + } else { + /* + * New data is of lesser origin precedence, + * so we just reject the update attempt. + */ + return (EACCES); + } + + strncpy(abuf, unisig_addr_print(atmsub), sizeof(abuf)); + log(LOG_WARNING, + "uniarp: ATM address for %s changed to %s,%s\n", + inet_ntoa(*ip), unisig_addr_print(atm), abuf); + } + + /* + * Update the cache entry with the new data + */ + ATM_ADDR_COPY(atm, &ipuap->ua_dstatm); + ATM_ADDR_COPY(atmsub, &ipuap->ua_dstatmsub); + ipuap->ua_intf = uip; + +dataok: + /* + * Update cache data origin + */ + ipuap->ua_origin = MAX(ipuap->ua_origin, origin); + + /* + * Ok, now act on this new/updated cache data + */ + ipuap->ua_flags |= UAF_LOCKED; + + /* + * Save pointer to last VCC currently on cached entry chain that + * will need to be notified of the map becoming valid + */ + itail = NULL; + if ((ipuap->ua_flags & UAF_VALID) == 0) { + + for (itail = ipuap->ua_ivp; itail && itail->iv_arpnext; + itail = itail->iv_arpnext) { + } + } + + /* + * If there was a 'nomap' entry for this mapping, then we need to + * announce the new mapping to them first. + */ + if (nouap) { + + /* + * Move the VCCs from this entry to the cache entry and + * let them know there's a valid mapping now + */ + for (ivp = nouap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + + UNLINK(ivp, struct ipvcc, nouap->ua_ivp, iv_arpnext); + + LINK2TAIL(ivp, struct ipvcc, ipuap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)ipuap; + + (*inp->inf_arpnotify)(ivp, MAP_VALID); + } + + /* + * Unlink and free the 'nomap' entry + */ + UNLINK(nouap, struct uniarp, uniarp_nomaptab, ua_next); + UNIARP_CANCEL(nouap); + atm_free((caddr_t)nouap); + } + + /* + * Now, if this entry wasn't valid, notify the remaining VCCs + */ + if (itail) { + + for (ivp = ipuap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*inp->inf_arpnotify)(ivp, MAP_VALID); + if (ivp == itail) + break; + } + } + ipuap->ua_flags &= ~UAF_LOCKED; + + /* + * We now have a valid cache entry, so cancel any retry timer + * and reset the aging timeout + */ + UNIARP_CANCEL(ipuap); + if ((ipuap->ua_origin == UAO_REGISTER) && (origin != UAO_REGISTER)) { + if (((ipuap->ua_flags & UAF_VALID) == 0) || + (ipuap->ua_aging <= + UNIARP_SERVER_AGE - UNIARP_MIN_REFRESH)) { + ipuap->ua_flags |= UAF_REFRESH; + ipuap->ua_aging = UNIARP_SERVER_AGE; + ipuap->ua_retry = UNIARP_SERVER_RETRY; + } + } else { + if (uip->uip_arpstate == UIAS_SERVER_ACTIVE) { + ipuap->ua_aging = UNIARP_SERVER_AGE; + ipuap->ua_retry = UNIARP_SERVER_RETRY; + } else { + ipuap->ua_aging = UNIARP_CLIENT_AGE; + ipuap->ua_retry = UNIARP_CLIENT_RETRY; + } + ipuap->ua_flags |= UAF_REFRESH; + } + ipuap->ua_flags |= UAF_VALID; + ipuap->ua_flags &= ~UAF_USED; + return (0); +} + + +/* + * Process ARP data from a PVC + * + * The arp table cache is never updated with PVC information. + * + * Called at splnet. + * + * Arguments: + * ivp pointer to input PVC's IPVCC control block + * ip pointer to IP address structure + * atm pointer to ATM address structure + * atmsub pointer to ATM subaddress structure + * + * Returns: + * none + * + */ +void +uniarp_cache_pvc(ivp, ip, atm, atmsub) + struct ipvcc *ivp; + struct in_addr *ip; + Atm_addr *atm; + Atm_addr *atmsub; +{ + struct ip_nif *inp; + struct uniarp *uap; + +#ifdef DIAGNOSTIC + char buf[64]; + int vpi = 0, vci = 0; + + if ((ivp->iv_conn) && (ivp->iv_conn->co_connvc)) { + vpi = ivp->iv_conn->co_connvc->cvc_vcc->vc_vpi; + vci = ivp->iv_conn->co_connvc->cvc_vcc->vc_vci; + } + strncpy(buf, unisig_addr_print(atmsub), sizeof(buf)); + ATM_DEBUG5("cache_pvc: vcc=(%d,%d), ip=%s, atm=(%s,%s)\n", + vpi, vci, inet_ntoa(*ip), unisig_addr_print(atm), buf); +#endif + + /* + * Get PVC info + */ + inp = ivp->iv_ipnif; + uap = (struct uniarp *)ivp->iv_arpent; + + /* + * See if IP address for PVC has changed + */ + if (uap->ua_dstip.s_addr != ip->s_addr) { + if (uap->ua_dstip.s_addr != 0) + (*inp->inf_arpnotify)(ivp, MAP_CHANGED); + uap->ua_dstip.s_addr = ip->s_addr; + } + + /* + * Let IP/ATM know if address has become valid + */ + if ((uap->ua_flags & UAF_VALID) == 0) + (*inp->inf_arpnotify)(ivp, MAP_VALID); + uap->ua_flags |= UAF_VALID; + uap->ua_aging = UNIARP_CLIENT_AGE; + uap->ua_retry = UNIARP_CLIENT_RETRY; + + /* + * Save ATM addresses just for debugging + */ + ATM_ADDR_COPY(atm, &uap->ua_dstatm); + ATM_ADDR_COPY(atmsub, &uap->ua_dstatmsub); + + return; +} + + +/* + * Validate IP address + * + * Arguments: + * uip pointer to UNI IP interface + * ip pointer to IP address structure + * origin source of arp information + * + * Returns: + * 0 IP address is acceptable + * else invalid IP address + * + */ +int +uniarp_validate_ip(uip, ip, origin) + struct uniip *uip; + struct in_addr *ip; + u_int origin; +{ + struct uniarp_prf *upp; + int i; + + + /* + * Can't be multicast or broadcast address + */ + if (IN_MULTICAST(ntohl(ip->s_addr)) || +#if (defined(BSD) && (BSD >= 199306)) + in_broadcast(*ip, &uip->uip_ipnif->inf_nif->nif_if)) +#else + in_broadcast(*ip)) +#endif + return (1); + + /* + * For ATMARP registration information (including SCSP data), + * the address must be allowed by the interface's prefix list. + */ + if ((origin == UAO_REGISTER) || (origin == UAO_SCSP)) { + for (i = uip->uip_nprefix, upp = uip->uip_prefix; + i; i--, upp++) { + if ((ip->s_addr & upp->upf_mask.s_addr) == + upp->upf_addr.s_addr) + break; + } + if (i == 0) + return (1); + } + + return (0); +} + diff --git a/sys/netatm/uni/uniarp_input.c b/sys/netatm/uni/uniarp_input.c new file mode 100644 index 0000000..cceeaa9 --- /dev/null +++ b/sys/netatm/uni/uniarp_input.c @@ -0,0 +1,853 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: uniarp_input.c,v 1.10 1998/07/13 00:04:32 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * UNI ATMARP support (RFC1577) - Input packet processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: uniarp_input.c,v 1.10 1998/07/13 00:04:32 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/uniip_var.h> + + +/* + * Local functions + */ +static void proc_arp_req __P((struct ipvcc *, KBuffer *)); +static void proc_arp_rsp __P((struct ipvcc *, KBuffer *)); +static void proc_arp_nak __P((struct ipvcc *, KBuffer *)); +static void proc_inarp_req __P((struct ipvcc *, KBuffer *)); +static void proc_inarp_rsp __P((struct ipvcc *, KBuffer *)); + + +/* + * Local variables + */ +static Atm_addr satm; +static Atm_addr satmsub; +static Atm_addr tatm; +static Atm_addr tatmsub; +static struct in_addr sip; +static struct in_addr tip; + + +/* + * Process ATMARP Input Data + * + * Arguments: + * tok uniarp connection token (pointer to ipvcc) + * m pointer to input packet buffer chain + * + * Returns: + * none + * + */ +void +uniarp_cpcs_data(tok, m) + void *tok; + KBuffer *m; +{ + struct ipvcc *ivp = tok; + struct atmarp_hdr *ahp; + KBuffer *n; + int len, plen = sizeof(struct atmarp_hdr); + +#ifdef DIAGNOSTIC + if (uniarp_print) + uniarp_pdu_print(ivp, m, "receive"); +#endif + + /* + * Verify IP's VCC state + */ + if (ivp->iv_state != IPVCC_ACTIVE) { + goto bad; + } + + /* + * Get the fixed fields together + */ + if (KB_LEN(m) < sizeof(struct atmarp_hdr)) { + KB_PULLUP(m, sizeof(struct atmarp_hdr), m); + if (m == NULL) + goto bad; + } + + KB_DATASTART(m, ahp, struct atmarp_hdr *); + + /* + * Initial packet verification + */ + if ((ahp->ah_hrd != htons(ARP_ATMFORUM)) || + (ahp->ah_pro != htons(ETHERTYPE_IP))) + goto bad; + + /* + * Verify/gather source address fields + */ + if (len = (ahp->ah_shtl & ARP_TL_LMASK)) { + if (ahp->ah_shtl & ARP_TL_E164) { + if (len > sizeof(struct atm_addr_e164)) + goto bad; + satm.address_format = T_ATM_E164_ADDR; + } else { + if (len != sizeof(struct atm_addr_nsap)) + goto bad; + satm.address_format = T_ATM_ENDSYS_ADDR; + } + satm.address_length = len; + if (KB_COPYDATA(m, plen, len, (caddr_t)satm.address)) + goto bad; + plen += len; + } else { + satm.address_format = T_ATM_ABSENT; + satm.address_length = 0; + } + + if (len = (ahp->ah_sstl & ARP_TL_LMASK)) { + if (((ahp->ah_sstl & ARP_TL_TMASK) != ARP_TL_NSAPA) || + (len != sizeof(struct atm_addr_nsap))) + goto bad; + satmsub.address_format = T_ATM_ENDSYS_ADDR; + satmsub.address_length = len; + if (KB_COPYDATA(m, plen, len, (caddr_t)satmsub.address)) + goto bad; + plen += len; + } else { + satmsub.address_format = T_ATM_ABSENT; + satmsub.address_length = 0; + } + + if (len = ahp->ah_spln) { + if (len != sizeof(struct in_addr)) + goto bad; + if (KB_COPYDATA(m, plen, len, (caddr_t)&sip)) + goto bad; + plen += len; + } else { + sip.s_addr = 0; + } + + /* + * Verify/gather target address fields + */ + if (len = (ahp->ah_thtl & ARP_TL_LMASK)) { + if (ahp->ah_thtl & ARP_TL_E164) { + if (len > sizeof(struct atm_addr_e164)) + goto bad; + tatm.address_format = T_ATM_E164_ADDR; + } else { + if (len != sizeof(struct atm_addr_nsap)) + goto bad; + tatm.address_format = T_ATM_ENDSYS_ADDR; + } + tatm.address_length = len; + if (KB_COPYDATA(m, plen, len, (caddr_t)tatm.address)) + goto bad; + plen += len; + } else { + tatm.address_format = T_ATM_ABSENT; + tatm.address_length = 0; + } + + if (len = (ahp->ah_tstl & ARP_TL_LMASK)) { + if (((ahp->ah_tstl & ARP_TL_TMASK) != ARP_TL_NSAPA) || + (len != sizeof(struct atm_addr_nsap))) + goto bad; + tatmsub.address_format = T_ATM_ENDSYS_ADDR; + tatmsub.address_length = len; + if (KB_COPYDATA(m, plen, len, (caddr_t)tatmsub.address)) + goto bad; + plen += len; + } else { + tatmsub.address_format = T_ATM_ABSENT; + tatmsub.address_length = 0; + } + + if (len = ahp->ah_tpln) { + if (len != sizeof(struct in_addr)) + goto bad; + if (KB_COPYDATA(m, plen, len, (caddr_t)&tip)) + goto bad; + plen += len; + } else { + tip.s_addr = 0; + } + + /* + * Verify packet length + */ + for (len = 0, n = m; n; n = KB_NEXT(n)) + len += KB_LEN(n); + if (len != plen) + goto bad; + + /* + * Now finish with packet-specific processing + */ + switch (ntohs(ahp->ah_op)) { + case ARP_REQUEST: + proc_arp_req(ivp, m); + break; + + case ARP_REPLY: + proc_arp_rsp(ivp, m); + break; + + case INARP_REQUEST: + proc_inarp_req(ivp, m); + break; + + case INARP_REPLY: + proc_inarp_rsp(ivp, m); + break; + + case ARP_NAK: + proc_arp_nak(ivp, m); + break; + + default: + goto bad; + } + + return; + +bad: + uniarp_stat.uas_rcvdrop++; + if (m) + KB_FREEALL(m); +} + + +/* + * Process an ATMARP request packet + * + * Arguments: + * ivp pointer to input VCC's IPVCC control block + * m pointer to input packet buffer chain + * + * Returns: + * none + * + */ +static void +proc_arp_req(ivp, m) + struct ipvcc *ivp; + KBuffer *m; +{ + struct ip_nif *inp; + struct atm_nif *nip; + struct siginst *sgp; + struct uniip *uip; + struct uniarp *uap; + struct in_addr myip; + int s = splnet(); + + /* + * Only an arp server should receive these + */ + inp = ivp->iv_ipnif; + nip = inp->inf_nif; + uip = (struct uniip *)inp->inf_isintf; + if ((uip == NULL) || + (uip->uip_arpstate != UIAS_SERVER_ACTIVE)) + goto drop; + + /* + * These should be sent only on SVCs + */ + if ((ivp->iv_flags & IVF_SVC) == 0) + goto drop; + + /* + * Locate our addresses + */ + sgp = nip->nif_pif->pif_siginst; + myip.s_addr = IA_SIN(inp->inf_addr)->sin_addr.s_addr; + + /* + * Target IP address must be present + */ + if (tip.s_addr == 0) + goto drop; + + /* + * Drop packet if both Source addresses aren't present + */ + if ((sip.s_addr == 0) || (satm.address_format == T_ATM_ABSENT)) + goto drop; + + /* + * Source addresses can't be ours + */ + if (ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &satm) && + ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, &satmsub)) { + struct vccb *vcp = ivp->iv_conn->co_connvc->cvc_vcc; + + log(LOG_WARNING, + "uniarp: vcc=(%d,%d) reports our ATM address\n", + vcp->vc_vpi, vcp->vc_vci); + goto drop; + } + if (sip.s_addr == myip.s_addr) { + struct vccb *vcp = ivp->iv_conn->co_connvc->cvc_vcc; + + log(LOG_WARNING, + "uniarp: vcc=(%d,%d) reports our IP address\n", + vcp->vc_vpi, vcp->vc_vci); + goto drop; + } + + /* + * Validate Source IP address + */ + if (uniarp_validate_ip(uip, &sip, UAO_REGISTER) != 0) + goto drop; + + /* + * If the source and target IP addresses are the same, then this + * must be a client registration request (RFC-2225). Otherwise, + * try to accomodate old clients (per RFC-2225 8.4.4). + */ + if (sip.s_addr == tip.s_addr) + (void) uniarp_cache_svc(uip, &sip, &satm, &satmsub, + UAO_REGISTER); + else { + uap = (struct uniarp *)ivp->iv_arpent; + if ((uap == NULL) || (uap->ua_origin < UAO_REGISTER)) + (void) uniarp_cache_svc(uip, &sip, &satm, &satmsub, + UAO_REGISTER); + } + + /* + * Lookup the target IP address in the cache (and also check if + * the query is for our address). + */ + UNIARP_LOOKUP(tip.s_addr, uap); + if (uap && (uap->ua_flags & UAF_VALID)) { + /* + * We've found a valid mapping + */ + (void) uniarp_arp_rsp(uip, &uap->ua_arpmap, &sip, &satm, + &satmsub, ivp); + + } else if (tip.s_addr == myip.s_addr) { + /* + * We're the target, so respond accordingly + */ + (void) uniarp_arp_rsp(uip, &uip->uip_arpsvrmap, &sip, &satm, + &satmsub, ivp); + + } else { + /* + * We don't know who the target is, so NAK the query + */ + (void) uniarp_arp_nak(uip, m, ivp); + m = NULL; + } + +drop: + (void) splx(s); + if (m) + KB_FREEALL(m); + return; +} + + +/* + * Process an ATMARP reply packet + * + * Arguments: + * ivp pointer to input VCC's IPVCC control block + * m pointer to input packet buffer chain + * + * Returns: + * none + * + */ +static void +proc_arp_rsp(ivp, m) + struct ipvcc *ivp; + KBuffer *m; +{ + struct ip_nif *inp; + struct atm_nif *nip; + struct siginst *sgp; + struct uniip *uip; + struct uniarp *uap; + struct in_addr myip; + int s = splnet(); + + /* + * Only the arp server should send these + */ + inp = ivp->iv_ipnif; + nip = inp->inf_nif; + uip = (struct uniip *)inp->inf_isintf; + if ((uip == NULL) || + (uip->uip_arpsvrvcc != ivp)) + goto drop; + + /* + * Locate our addresses + */ + sgp = nip->nif_pif->pif_siginst; + myip.s_addr = IA_SIN(inp->inf_addr)->sin_addr.s_addr; + + /* + * Target addresses must be ours + */ + if ((tip.s_addr != myip.s_addr) || + !ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &tatm) || + !ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, &tatmsub)) + goto drop; + + /* + * Drop packet if both Source addresses aren't present + */ + if ((sip.s_addr == 0) || (satm.address_format == T_ATM_ABSENT)) + goto drop; + + /* + * If the Source addresses are ours, this is an arp server + * registration response + */ + if (ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &satm) && + ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, &satmsub)) { + if (sip.s_addr == myip.s_addr) { + /* + * Registration response - update our state and + * set a registration refresh timer + */ + if (uip->uip_arpstate == UIAS_CLIENT_REGISTER) + uip->uip_arpstate = UIAS_CLIENT_ACTIVE; + + if (uip->uip_arpstate == UIAS_CLIENT_ACTIVE) { + UNIIP_ARP_CANCEL(uip); + UNIIP_ARP_TIMER(uip, UNIARP_REGIS_REFRESH); + } + + /* + * If the cache entry for the server VCC isn't valid + * yet, then send an Inverse ATMARP request to solicit + * the server's IP address + */ + uap = (struct uniarp *)ivp->iv_arpent; + if ((uap->ua_flags & UAF_VALID) == 0) { + (void) uniarp_inarp_req(uip, &uap->ua_dstatm, + &uap->ua_dstatmsub, ivp); + } + goto drop; + } else { + log(LOG_WARNING, + "uniarp: arpserver has our IP address wrong\n"); + goto drop; + } + } else if (sip.s_addr == myip.s_addr) { + log(LOG_WARNING, + "uniarp: arpserver has our ATM address wrong\n"); + goto drop; + } + + /* + * Validate the Source IP address + */ + if (uniarp_validate_ip(uip, &sip, UAO_LOOKUP) != 0) + goto drop; + + /* + * Now we believe this packet contains an authoritative mapping, + * which we probably need to setup an outgoing SVC connection + */ + (void) uniarp_cache_svc(uip, &sip, &satm, &satmsub, UAO_LOOKUP); + +drop: + (void) splx(s); + KB_FREEALL(m); + return; +} + + +/* + * Process an ATMARP negative ack packet + * + * Arguments: + * ivp pointer to input VCC's IPVCC control block + * m pointer to input packet buffer chain + * + * Returns: + * none + * + */ +static void +proc_arp_nak(ivp, m) + struct ipvcc *ivp; + KBuffer *m; +{ + struct ip_nif *inp; + struct atm_nif *nip; + struct siginst *sgp; + struct uniip *uip; + struct uniarp *uap; + struct in_addr myip; + struct ipvcc *inext; + int s = splnet(); + + /* + * Only the arp server should send these + */ + inp = ivp->iv_ipnif; + nip = inp->inf_nif; + uip = (struct uniip *)inp->inf_isintf; + if ((uip == NULL) || + (uip->uip_arpsvrvcc != ivp)) + goto drop; + + /* + * Locate our addresses + */ + sgp = nip->nif_pif->pif_siginst; + myip.s_addr = IA_SIN(inp->inf_addr)->sin_addr.s_addr; + + /* + * Source addresses must be ours + */ + if ((sip.s_addr != myip.s_addr) || + !ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &satm) || + !ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, &satmsub)) + goto drop; + + /* + * Drop packet if the Target IP address isn't there or if this + * is a registration response, indicating an old or flakey server + */ + if ((tip.s_addr == 0) || (tip.s_addr == myip.s_addr)) + goto drop; + + /* + * Otherwise, see who we were looking for + */ + UNIARP_LOOKUP(tip.s_addr, uap); + if (uap == NULL) + goto drop; + + /* + * This entry isn't valid any longer, so notify all VCCs using this + * entry that they must finish up. The last notify should cause + * this entry to be freed by the vcclose() function. + */ + uap->ua_flags &= ~UAF_VALID; + for (ivp = uap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*inp->inf_arpnotify)(ivp, MAP_FAILED); + } + +drop: + (void) splx(s); + KB_FREEALL(m); + return; +} + + +/* + * Process an InATMARP request packet + * + * Arguments: + * ivp pointer to input VCC's IPVCC control block + * m pointer to input packet buffer chain + * + * Returns: + * none + * + */ +static void +proc_inarp_req(ivp, m) + struct ipvcc *ivp; + KBuffer *m; +{ + struct ip_nif *inp; + struct atm_nif *nip; + struct siginst *sgp; + struct uniip *uip; + struct in_addr myip; + int s = splnet(); + + /* + * Get interface pointers + */ + inp = ivp->iv_ipnif; + nip = inp->inf_nif; + uip = (struct uniip *)inp->inf_isintf; + if (uip == NULL) + goto drop; + + /* + * Locate our addresses + */ + sgp = nip->nif_pif->pif_siginst; + myip.s_addr = IA_SIN(inp->inf_addr)->sin_addr.s_addr; + + /* + * Packet must have a Source IP address and, if it was received + * over an SVC, a Source ATM address too. + */ + if ((sip.s_addr == 0) || + ((ivp->iv_flags & IVF_SVC) && (satm.address_format == T_ATM_ABSENT))) + goto drop; + + /* + * Validate Source ATM address + * - can't be me + */ + if (satm.address_format != T_ATM_ABSENT) { + if (ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &satm) && + ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, + &satmsub)) + goto drop; + } + + /* + * Validate Source IP address + */ + if ((sip.s_addr == myip.s_addr) || + (uniarp_validate_ip(uip, &sip, UAO_PEER_REQ) != 0)) + goto drop; + + /* + * The Target ATM address is required for a packet received over + * an SVC, optional for a PVC. If one is present, it must be our + * address. + */ + if ((ivp->iv_flags & IVF_SVC) && (tatm.address_format == T_ATM_ABSENT)) + goto drop; + if ((tatm.address_format != T_ATM_ABSENT) && + (!ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &tatm) || + !ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, &tatmsub))) + goto drop; + + /* + * See where this packet is from + */ + if (ivp->iv_flags & IVF_PVC) { + /* + * Process the PVC arp data, although we don't really + * update the arp cache with this information + */ + uniarp_cache_pvc(ivp, &sip, &satm, &satmsub); + + } else if (uip->uip_arpsvrvcc == ivp) { + /* + * Packet is from the arp server, so we've received a + * registration/refresh request (1577 version). + * + * Therefore, update cache with authoritative data. + */ + (void) uniarp_cache_svc(uip, &sip, &satm, &satmsub, UAO_LOOKUP); + + /* + * Make sure the cache update didn't kill the server VCC + */ + if (uip->uip_arpsvrvcc != ivp) + goto drop; + + /* + * Update the server state and set the + * registration refresh timer + */ + uip->uip_arpstate = UIAS_CLIENT_ACTIVE; + UNIIP_ARP_CANCEL(uip); + UNIIP_ARP_TIMER(uip, UNIARP_REGIS_REFRESH); + } else { + /* + * Otherwise, we consider this source mapping data as + * non-authoritative and update the cache appropriately + */ + if (uniarp_cache_svc(uip, &sip, &satm, &satmsub, UAO_PEER_REQ)) + goto drop; + } + + /* + * Send an InATMARP response back to originator + */ + (void) uniarp_inarp_rsp(uip, &sip, &satm, &satmsub, ivp); + +drop: + (void) splx(s); + KB_FREEALL(m); + return; +} + + +/* + * Process an InATMARP response packet + * + * Arguments: + * ivp pointer to input VCC's IPVCC control block + * m pointer to input packet buffer chain + * + * Returns: + * none + * + */ +static void +proc_inarp_rsp(ivp, m) + struct ipvcc *ivp; + KBuffer *m; +{ + struct ip_nif *inp; + struct atm_nif *nip; + struct siginst *sgp; + struct uniip *uip; + struct uniarp *uap; + struct in_addr myip; + int s = splnet(); + + /* + * Get interface pointers + */ + inp = ivp->iv_ipnif; + nip = inp->inf_nif; + uip = (struct uniip *)inp->inf_isintf; + if (uip == NULL) + goto drop; + + /* + * Locate our addresses + */ + sgp = nip->nif_pif->pif_siginst; + myip.s_addr = IA_SIN(inp->inf_addr)->sin_addr.s_addr; + + /* + * Packet must have a Source IP address and, if it was received + * over an SVC, a Source ATM address too. + */ + if ((sip.s_addr == 0) || + ((ivp->iv_flags & IVF_SVC) && (satm.address_format == T_ATM_ABSENT))) + goto drop; + + /* + * Validate Source ATM address + * - can't be me + */ + if (satm.address_format != T_ATM_ABSENT) { + if (ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &satm) && + ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, + &satmsub)) + goto drop; + } + + /* + * Validate Source IP address + * - must be in our LIS + * - can't be me + * - can't be broadcast + * - can't be multicast + */ + if ((sip.s_addr == myip.s_addr) || + (uniarp_validate_ip(uip, &sip, UAO_PEER_RSP) != 0)) + goto drop; + + /* + * The Target ATM address is required for a packet received over + * an SVC, optional for a PVC. If one is present, it must be our + * address. + */ + if ((ivp->iv_flags & IVF_SVC) && (tatm.address_format == T_ATM_ABSENT)) + goto drop; + if ((tatm.address_format != T_ATM_ABSENT) && + (!ATM_ADDR_SEL_EQUAL(&sgp->si_addr, nip->nif_sel, &tatm) || + !ATM_ADDR_SEL_EQUAL(&sgp->si_subaddr, nip->nif_sel, &tatmsub))) + goto drop; + + /* + * See where this packet is from + */ + if (ivp->iv_flags & IVF_PVC) { + /* + * Process the PVC arp data, although we don't really + * update the arp cache with this information + */ + uniarp_cache_pvc(ivp, &sip, &satm, &satmsub); + + } else { + /* + * Can't tell the difference between an RFC-1577 registration + * and a data connection from a client of another arpserver + * on our LIS (using SCSP) - so we'll update the cache now + * with what we've got. Our clients will get "registered" + * when (if) they query us with an arp request. + */ + (void) uniarp_cache_svc(uip, &sip, &satm, &satmsub, + UAO_PEER_RSP); + } + +drop: + (void) splx(s); + KB_FREEALL(m); + return; +} + + +/* + * Print an ATMARP PDU + * + * Arguments: + * ivp pointer to input VCC control block + * m pointer to pdu buffer chain + * msg pointer to message string + * + * Returns: + * none + * + */ +void +uniarp_pdu_print(ivp, m, msg) + struct ipvcc *ivp; + KBuffer *m; + char *msg; +{ + char buf[128]; + struct vccb *vcp; + + vcp = ivp->iv_conn->co_connvc->cvc_vcc; + sprintf(buf, "uniarp %s: vcc=(%d,%d)\n", msg, vcp->vc_vpi, vcp->vc_vci); + atm_pdu_print(m, buf); +} + diff --git a/sys/netatm/uni/uniarp_output.c b/sys/netatm/uni/uniarp_output.c new file mode 100644 index 0000000..81fab93 --- /dev/null +++ b/sys/netatm/uni/uniarp_output.c @@ -0,0 +1,797 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: uniarp_output.c,v 1.7 1998/06/29 22:15:41 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * UNI ATMARP support (RFC1577) - Output packet processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: uniarp_output.c,v 1.7 1998/06/29 22:15:41 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include <netatm/uni/uniip_var.h> + + +/* + * Issue an ATMARP Request PDU + * + * Arguments: + * uip pointer to IP interface + * tip pointer to target IP address + * + * Returns: + * 0 PDU was successfully sent + * else unable to send PDU + * + */ +int +uniarp_arp_req(uip, tip) + struct uniip *uip; + struct in_addr *tip; +{ + KBuffer *m; + struct atmarp_hdr *ahp; + struct atm_nif *nip; + struct ip_nif *inp; + struct ipvcc *ivp; + struct siginst *sip; + char *cp; + int len, err; + + inp = uip->uip_ipnif; + nip = inp->inf_nif; + sip = inp->inf_nif->nif_pif->pif_siginst; + + /* + * Figure out how long pdu is going to be + */ + len = sizeof(struct atmarp_hdr) + (2 * sizeof(struct in_addr)); + switch (sip->si_addr.address_format) { + case T_ATM_ENDSYS_ADDR: + len += sip->si_addr.address_length; + break; + + case T_ATM_E164_ADDR: + len += sip->si_addr.address_length; + if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) + len += sip->si_subaddr.address_length; + break; + } + + /* + * Get a buffer for pdu + */ + KB_ALLOCPKT(m, len, KB_F_NOWAIT, KB_T_DATA); + if (m == NULL) + return (1); + + /* + * Place aligned pdu at end of buffer + */ + KB_TAILALIGN(m, len); + KB_DATASTART(m, ahp, struct atmarp_hdr *); + + /* + * Setup variable fields pointer + */ + cp = (char *)ahp + sizeof(struct atmarp_hdr); + + /* + * Build fields + */ + ahp->ah_hrd = htons(ARP_ATMFORUM); + ahp->ah_pro = htons(ETHERTYPE_IP); + len = sip->si_addr.address_length; + switch (sip->si_addr.address_format) { + case T_ATM_ENDSYS_ADDR: + ahp->ah_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_sha */ + KM_COPY(sip->si_addr.address, cp, len - 1); + ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel; + cp += len; + + ahp->ah_sstl = 0; + break; + + case T_ATM_E164_ADDR: + ahp->ah_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK); + + /* ah_sha */ + KM_COPY(sip->si_addr.address, cp, len); + cp += len; + + if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) { + len = sip->si_subaddr.address_length; + ahp->ah_sstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_ssa */ + KM_COPY(sip->si_subaddr.address, cp, len - 1); + ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel; + cp += len; + } else + ahp->ah_sstl = 0; + break; + + default: + ahp->ah_shtl = 0; + ahp->ah_sstl = 0; + } + + ahp->ah_op = htons(ARP_REQUEST); + ahp->ah_spln = sizeof(struct in_addr); + + /* ah_spa */ + KM_COPY((caddr_t)&(IA_SIN(inp->inf_addr)->sin_addr), cp, + sizeof(struct in_addr)); + cp += sizeof(struct in_addr); + + ahp->ah_thtl = 0; + ahp->ah_tstl = 0; + + ahp->ah_tpln = sizeof(struct in_addr); + + /* ah_tpa */ + KM_COPY((caddr_t)tip, cp, sizeof(struct in_addr)); + + /* + * Finally, send the pdu to the ATMARP server + */ + ivp = uip->uip_arpsvrvcc; + if (uniarp_print) + uniarp_pdu_print(ivp, m, "send"); + err = atm_cm_cpcs_data(ivp->iv_arpconn, m); + if (err) { + /* + * Didn't make it + */ + KB_FREEALL(m); + return (1); + } + + return (0); +} + + +/* + * Issue an ATMARP Response PDU + * + * Arguments: + * uip pointer to IP interface + * amp pointer to source map entry + * tip pointer to target IP address + * tatm pointer to target ATM address + * tsub pointer to target ATM subaddress + * ivp pointer to vcc over which to send pdu + * + * Returns: + * 0 PDU was successfully sent + * else unable to send PDU + * + */ +int +uniarp_arp_rsp(uip, amp, tip, tatm, tsub, ivp) + struct uniip *uip; + struct arpmap *amp; + struct in_addr *tip; + Atm_addr *tatm; + Atm_addr *tsub; + struct ipvcc *ivp; +{ + KBuffer *m; + struct atmarp_hdr *ahp; + char *cp; + int len, err; + + /* + * Figure out how long pdu is going to be + */ + len = sizeof(struct atmarp_hdr) + (2 * sizeof(struct in_addr)); + switch (amp->am_dstatm.address_format) { + case T_ATM_ENDSYS_ADDR: + len += amp->am_dstatm.address_length; + break; + + case T_ATM_E164_ADDR: + len += amp->am_dstatm.address_length; + if (amp->am_dstatmsub.address_format == T_ATM_ENDSYS_ADDR) + len += amp->am_dstatmsub.address_length; + break; + } + + switch (tatm->address_format) { + case T_ATM_ENDSYS_ADDR: + len += tatm->address_length; + break; + + case T_ATM_E164_ADDR: + len += tatm->address_length; + if (tsub->address_format == T_ATM_ENDSYS_ADDR) + len += tsub->address_length; + break; + } + + /* + * Get a buffer for pdu + */ + KB_ALLOCPKT(m, len, KB_F_NOWAIT, KB_T_DATA); + if (m == NULL) + return (1); + + /* + * Place aligned pdu at end of buffer + */ + KB_TAILALIGN(m, len); + KB_DATASTART(m, ahp, struct atmarp_hdr *); + + /* + * Setup variable fields pointer + */ + cp = (char *)ahp + sizeof(struct atmarp_hdr); + + /* + * Build fields + */ + ahp->ah_hrd = htons(ARP_ATMFORUM); + ahp->ah_pro = htons(ETHERTYPE_IP); + len = amp->am_dstatm.address_length; + switch (amp->am_dstatm.address_format) { + case T_ATM_ENDSYS_ADDR: + ahp->ah_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_sha */ + KM_COPY(amp->am_dstatm.address, cp, len); + cp += len; + + ahp->ah_sstl = 0; + break; + + case T_ATM_E164_ADDR: + ahp->ah_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK); + + /* ah_sha */ + KM_COPY(amp->am_dstatm.address, cp, len); + cp += len; + + if (amp->am_dstatmsub.address_format == T_ATM_ENDSYS_ADDR) { + len = amp->am_dstatmsub.address_length; + ahp->ah_sstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_ssa */ + KM_COPY(amp->am_dstatmsub.address, cp, len); + cp += len; + } else + ahp->ah_sstl = 0; + break; + + default: + ahp->ah_shtl = 0; + ahp->ah_sstl = 0; + } + + ahp->ah_op = htons(ARP_REPLY); + ahp->ah_spln = sizeof(struct in_addr); + + /* ah_spa */ + KM_COPY((caddr_t)&->am_dstip, cp, sizeof(struct in_addr)); + cp += sizeof(struct in_addr); + + len = tatm->address_length; + switch (tatm->address_format) { + case T_ATM_ENDSYS_ADDR: + ahp->ah_thtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_tha */ + KM_COPY(tatm->address, cp, len); + cp += len; + + ahp->ah_tstl = 0; + break; + + case T_ATM_E164_ADDR: + ahp->ah_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK); + + /* ah_tha */ + KM_COPY(tatm->address, cp, len); + cp += len; + + if (tsub->address_format == T_ATM_ENDSYS_ADDR) { + len = tsub->address_length; + ahp->ah_tstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_tsa */ + KM_COPY(tsub->address, cp, len); + cp += len; + } else + ahp->ah_tstl = 0; + break; + + default: + ahp->ah_thtl = 0; + ahp->ah_tstl = 0; + } + + ahp->ah_tpln = sizeof(struct in_addr); + + /* ah_tpa */ + KM_COPY((caddr_t)tip, cp, sizeof(struct in_addr)); + + /* + * Finally, send the pdu to the vcc peer + */ + if (uniarp_print) + uniarp_pdu_print(ivp, m, "send"); + err = atm_cm_cpcs_data(ivp->iv_arpconn, m); + if (err) { + /* + * Didn't make it + */ + KB_FREEALL(m); + return (1); + } + + return (0); +} + + +/* + * Issue an ATMARP NAK PDU + * + * Arguments: + * uip pointer to IP interface + * m pointer to ATMARP_REQ buffer chain + * ivp pointer to vcc over which to send pdu + * + * Returns: + * 0 PDU was successfully sent + * else unable to send PDU + * + */ +int +uniarp_arp_nak(uip, m, ivp) + struct uniip *uip; + KBuffer *m; + struct ipvcc *ivp; +{ + struct atmarp_hdr *ahp; + int err; + + /* + * Get the fixed fields together + */ + if (KB_LEN(m) < sizeof(struct atmarp_hdr)) { + KB_PULLUP(m, sizeof(struct atmarp_hdr), m); + if (m == NULL) + return (1); + } + KB_DATASTART(m, ahp, struct atmarp_hdr *); + + /* + * Set new op-code + */ + ahp->ah_op = htons(ARP_NAK); + + /* + * Finally, send the pdu to the vcc peer + */ + if (uniarp_print) + uniarp_pdu_print(ivp, m, "send"); + err = atm_cm_cpcs_data(ivp->iv_arpconn, m); + if (err) { + /* + * Didn't make it + */ + KB_FREEALL(m); + return (1); + } + + return (0); +} + + +/* + * Issue an InATMARP Request PDU + * + * Arguments: + * uip pointer to IP interface + * tatm pointer to target ATM address + * tsub pointer to target ATM subaddress + * ivp pointer to vcc over which to send pdu + * + * Returns: + * 0 PDU was successfully sent + * else unable to send PDU + * + */ +int +uniarp_inarp_req(uip, tatm, tsub, ivp) + struct uniip *uip; + Atm_addr *tatm; + Atm_addr *tsub; + struct ipvcc *ivp; +{ + KBuffer *m; + struct atmarp_hdr *ahp; + struct atm_nif *nip; + struct ip_nif *inp; + struct siginst *sip; + char *cp; + int len, err; + + inp = uip->uip_ipnif; + nip = inp->inf_nif; + sip = inp->inf_nif->nif_pif->pif_siginst; + + /* + * Figure out how long pdu is going to be + */ + len = sizeof(struct atmarp_hdr) + sizeof(struct in_addr); + switch (sip->si_addr.address_format) { + case T_ATM_ENDSYS_ADDR: + len += sip->si_addr.address_length; + break; + + case T_ATM_E164_ADDR: + len += sip->si_addr.address_length; + if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) + len += sip->si_subaddr.address_length; + break; + } + + switch (tatm->address_format) { + case T_ATM_ENDSYS_ADDR: + len += tatm->address_length; + break; + + case T_ATM_E164_ADDR: + len += tatm->address_length; + if (tsub->address_format == T_ATM_ENDSYS_ADDR) + len += tsub->address_length; + break; + } + + /* + * Get a buffer for pdu + */ + KB_ALLOCPKT(m, len, KB_F_NOWAIT, KB_T_DATA); + if (m == NULL) + return (1); + + /* + * Place aligned pdu at end of buffer + */ + KB_TAILALIGN(m, len); + KB_DATASTART(m, ahp, struct atmarp_hdr *); + + /* + * Setup variable fields pointer + */ + cp = (char *)ahp + sizeof(struct atmarp_hdr); + + /* + * Build fields + */ + ahp->ah_hrd = htons(ARP_ATMFORUM); + ahp->ah_pro = htons(ETHERTYPE_IP); + len = sip->si_addr.address_length; + switch (sip->si_addr.address_format) { + case T_ATM_ENDSYS_ADDR: + ahp->ah_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_sha */ + KM_COPY(sip->si_addr.address, cp, len - 1); + ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel; + cp += len; + + ahp->ah_sstl = 0; + break; + + case T_ATM_E164_ADDR: + ahp->ah_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK); + + /* ah_sha */ + KM_COPY(sip->si_addr.address, cp, len); + cp += len; + + if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) { + len = sip->si_subaddr.address_length; + ahp->ah_sstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_ssa */ + KM_COPY(sip->si_subaddr.address, cp, len - 1); + ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel; + cp += len; + } else + ahp->ah_sstl = 0; + break; + + default: + ahp->ah_shtl = 0; + ahp->ah_sstl = 0; + } + + ahp->ah_op = htons(INARP_REQUEST); + ahp->ah_spln = sizeof(struct in_addr); + + /* ah_spa */ + KM_COPY((caddr_t)&(IA_SIN(inp->inf_addr)->sin_addr), cp, + sizeof(struct in_addr)); + cp += sizeof(struct in_addr); + + len = tatm->address_length; + switch (tatm->address_format) { + case T_ATM_ENDSYS_ADDR: + ahp->ah_thtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_tha */ + KM_COPY(tatm->address, cp, len); + cp += len; + + ahp->ah_tstl = 0; + break; + + case T_ATM_E164_ADDR: + ahp->ah_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK); + + /* ah_tha */ + KM_COPY(tatm->address, cp, len); + cp += len; + + if (tsub->address_format == T_ATM_ENDSYS_ADDR) { + len = tsub->address_length; + ahp->ah_tstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_tsa */ + KM_COPY(tsub->address, cp, len); + cp += len; + } else + ahp->ah_tstl = 0; + break; + + default: + ahp->ah_thtl = 0; + ahp->ah_tstl = 0; + } + + ahp->ah_tpln = 0; + + /* + * Finally, send the pdu to the vcc peer + */ + if (uniarp_print) + uniarp_pdu_print(ivp, m, "send"); + err = atm_cm_cpcs_data(ivp->iv_arpconn, m); + if (err) { + /* + * Didn't make it + */ + KB_FREEALL(m); + return (1); + } + + return (0); +} + + +/* + * Issue an InATMARP Response PDU + * + * Arguments: + * uip pointer to IP interface + * tip pointer to target IP address + * tatm pointer to target ATM address + * tsub pointer to target ATM subaddress + * ivp pointer to vcc over which to send pdu + * + * Returns: + * 0 PDU was successfully sent + * else unable to send PDU + * + */ +int +uniarp_inarp_rsp(uip, tip, tatm, tsub, ivp) + struct uniip *uip; + struct in_addr *tip; + Atm_addr *tatm; + Atm_addr *tsub; + struct ipvcc *ivp; +{ + KBuffer *m; + struct atmarp_hdr *ahp; + struct atm_nif *nip; + struct ip_nif *inp; + struct siginst *sip; + char *cp; + int len, err; + + inp = uip->uip_ipnif; + nip = inp->inf_nif; + sip = inp->inf_nif->nif_pif->pif_siginst; + + /* + * Figure out how long pdu is going to be + */ + len = sizeof(struct atmarp_hdr) + (2 * sizeof(struct in_addr)); + switch (sip->si_addr.address_format) { + case T_ATM_ENDSYS_ADDR: + len += sip->si_addr.address_length; + break; + + case T_ATM_E164_ADDR: + len += sip->si_addr.address_length; + if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) + len += sip->si_subaddr.address_length; + break; + } + + switch (tatm->address_format) { + case T_ATM_ENDSYS_ADDR: + len += tatm->address_length; + break; + + case T_ATM_E164_ADDR: + len += tatm->address_length; + if (tsub->address_format == T_ATM_ENDSYS_ADDR) + len += tsub->address_length; + break; + } + + /* + * Get a buffer for pdu + */ + KB_ALLOCPKT(m, len, KB_F_NOWAIT, KB_T_DATA); + if (m == NULL) + return (1); + + /* + * Place aligned pdu at end of buffer + */ + KB_TAILALIGN(m, len); + KB_DATASTART(m, ahp, struct atmarp_hdr *); + + /* + * Setup variable fields pointer + */ + cp = (char *)ahp + sizeof(struct atmarp_hdr); + + /* + * Build fields + */ + ahp->ah_hrd = htons(ARP_ATMFORUM); + ahp->ah_pro = htons(ETHERTYPE_IP); + len = sip->si_addr.address_length; + switch (sip->si_addr.address_format) { + case T_ATM_ENDSYS_ADDR: + ahp->ah_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_sha */ + KM_COPY(sip->si_addr.address, cp, len - 1); + ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel; + cp += len; + + ahp->ah_sstl = 0; + break; + + case T_ATM_E164_ADDR: + ahp->ah_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK); + + /* ah_sha */ + KM_COPY(sip->si_addr.address, cp, len); + cp += len; + + if (sip->si_subaddr.address_format == T_ATM_ENDSYS_ADDR) { + len = sip->si_subaddr.address_length; + ahp->ah_sstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_ssa */ + KM_COPY(sip->si_subaddr.address, cp, len - 1); + ((struct atm_addr_nsap *)cp)->aan_sel = nip->nif_sel; + cp += len; + } else + ahp->ah_sstl = 0; + break; + + default: + ahp->ah_shtl = 0; + ahp->ah_sstl = 0; + } + + ahp->ah_op = htons(INARP_REPLY); + ahp->ah_spln = sizeof(struct in_addr); + + /* ah_spa */ + KM_COPY((caddr_t)&(IA_SIN(inp->inf_addr)->sin_addr), cp, + sizeof(struct in_addr)); + cp += sizeof(struct in_addr); + + len = tatm->address_length; + switch (tatm->address_format) { + case T_ATM_ENDSYS_ADDR: + ahp->ah_thtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_tha */ + KM_COPY(tatm->address, cp, len); + cp += len; + + ahp->ah_tstl = 0; + break; + + case T_ATM_E164_ADDR: + ahp->ah_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK); + + /* ah_tha */ + KM_COPY(tatm->address, cp, len); + cp += len; + + if (tsub->address_format == T_ATM_ENDSYS_ADDR) { + len = tsub->address_length; + ahp->ah_tstl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* ah_tsa */ + KM_COPY(tsub->address, cp, len); + cp += len; + } else + ahp->ah_tstl = 0; + break; + + default: + ahp->ah_thtl = 0; + ahp->ah_tstl = 0; + } + + ahp->ah_tpln = sizeof(struct in_addr); + + /* ah_tpa */ + KM_COPY((caddr_t)tip, cp, sizeof(struct in_addr)); + + /* + * Finally, send the pdu to the vcc peer + */ + if (uniarp_print) + uniarp_pdu_print(ivp, m, "send"); + err = atm_cm_cpcs_data(ivp->iv_arpconn, m); + if (err) { + /* + * Didn't make it + */ + KB_FREEALL(m); + return (1); + } + + return (0); +} + diff --git a/sys/netatm/uni/uniarp_timer.c b/sys/netatm/uni/uniarp_timer.c new file mode 100644 index 0000000..1f00202 --- /dev/null +++ b/sys/netatm/uni/uniarp_timer.c @@ -0,0 +1,320 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: uniarp_timer.c,v 1.8 1998/06/29 22:44:31 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * UNI ATMARP support (RFC1577) - Timer processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: uniarp_timer.c,v 1.8 1998/06/29 22:44:31 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/uniip_var.h> + + +/* + * Local functions + */ +static void uniarp_svc_oldage __P((struct uniarp *)); +static void uniarp_pvc_oldage __P((struct uniarp *)); + + +/* + * Process a UNI ATMARP entry timeout + * + * Called when a previously scheduled uniarp control block timer expires. + * + * Called at splnet. + * + * Arguments: + * tip pointer to uniarp timer control block + * + * Returns: + * none + * + */ +void +uniarp_timeout(tip) + struct atm_time *tip; +{ + struct uniip *uip; + struct uniarp *uap; + struct ipvcc *ivp; + + + /* + * Back-off to uniarp control block + */ + uap = (struct uniarp *) + ((caddr_t)tip - (int)(&((struct uniarp *)0)->ua_time)); + uip = uap->ua_intf; + + + /* + * Do we know the IP address for this entry yet?? + */ + if (uap->ua_dstip.s_addr == 0) { + + /* + * No, then send another InATMARP_REQ on each active VCC + * associated with this entry to solicit the peer's identity. + */ + for (ivp = uap->ua_ivp; ivp; ivp = ivp->iv_arpnext) { + if (ivp->iv_state != IPVCC_ACTIVE) + continue; + (void) uniarp_inarp_req(uip, &uap->ua_dstatm, + &uap->ua_dstatmsub, ivp); + } + + /* + * Restart retry timer + */ + UNIARP_TIMER(uap, UNIARP_ARP_RETRY); + } else { + /* + * Yes, then we're trying to find the ATM address for this + * IP address - so send another ATMARP_REQ to the arpserver + * (if it's up at the moment) + */ + if (uip->uip_arpstate == UIAS_CLIENT_ACTIVE) + (void) uniarp_arp_req(uip, &uap->ua_dstip); + + /* + * Restart retry timer + */ + UNIARP_TIMER(uap, UNIARP_ARP_RETRY); + } + + return; +} + + +/* + * Process an UNI ARP SVC entry aging timer expiration + * + * This function is called when an SVC arp entry's aging timer has expired. + * + * Called at splnet(). + * + * Arguments: + * uap pointer to atmarp table entry + * + * Returns: + * none + * + */ +static void +uniarp_svc_oldage(uap) + struct uniarp *uap; +{ + struct ipvcc *ivp, *inext; + struct uniip *uip = uap->ua_intf; + + + /* + * Permanent (manually installed) entries are never aged + */ + if (uap->ua_origin >= UAO_PERM) + return; + + /* + * If entry is valid and we're out of retrys, tell + * IP/ATM that the SVCs can't be used + */ + if ((uap->ua_flags & UAF_VALID) && (uap->ua_retry-- == 0)) { + uap->ua_flags |= UAF_LOCKED; + for (ivp = uap->ua_ivp; ivp; ivp = inext) { + inext = ivp->iv_arpnext; + (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_INVALID); + } + uap->ua_flags &= ~(UAF_LOCKED | UAF_VALID); + uap->ua_origin = 0; + + /* + * Delete and free an unused entry + */ + if (uap->ua_ivp == NULL) { + UNIARP_CANCEL(uap); + UNIARP_DELETE(uap); + atm_free((caddr_t)uap); + return; + } + } + + /* + * We want to try and refresh this entry but we don't want + * to keep unused entries laying around forever. + */ + if (uap->ua_ivp || (uap->ua_flags & UAF_USED)) { + if (uip->uip_arpstate == UIAS_CLIENT_ACTIVE) { + /* + * If we are a client (and the server VCC is active), + * then we'll ask the server for a refresh + */ + (void) uniarp_arp_req(uip, &uap->ua_dstip); + } else { + /* + * Otherwise, solicit the each active VCC peer with + * an Inverse ATMARP + */ + for (ivp = uap->ua_ivp; ivp; ivp = ivp->iv_arpnext) { + if (ivp->iv_state != IPVCC_ACTIVE) + continue; + (void) uniarp_inarp_req(uip, &uap->ua_dstatm, + &uap->ua_dstatmsub, ivp); + } + } + } + + /* + * Reset timeout + */ + if (uap->ua_flags & UAF_VALID) + uap->ua_aging = UNIARP_RETRY_AGE; + else + uap->ua_aging = UNIARP_REVALID_AGE; + + return; +} + + +/* + * Process an UNI ARP PVC entry aging timer expiration + * + * This function is called when a PVC arp entry's aging timer has expired. + * + * Called at splnet(). + * + * Arguments: + * uap pointer to atmarp table entry + * + * Returns: + * none + * + */ +static void +uniarp_pvc_oldage(uap) + struct uniarp *uap; +{ + struct ipvcc *ivp = uap->ua_ivp; + + /* + * If entry is valid and we're out of retrys, tell + * IP/ATM that PVC can't be used + */ + if ((uap->ua_flags & UAF_VALID) && (uap->ua_retry-- == 0)) { + (*ivp->iv_ipnif->inf_arpnotify)(ivp, MAP_INVALID); + uap->ua_flags &= ~UAF_VALID; + } + + /* + * Solicit peer with Inverse ATMARP + */ + (void) uniarp_inarp_req(uap->ua_intf, &uap->ua_dstatm, + &uap->ua_dstatmsub, ivp); + + /* + * Reset timeout + */ + if (uap->ua_flags & UAF_VALID) + uap->ua_aging = UNIARP_RETRY_AGE; + else + uap->ua_aging = UNIARP_REVALID_AGE; + + return; +} + + +/* + * Process a UNI ARP aging timer tick + * + * This function is called every UNIARP_AGING seconds, in order to age + * all the arp table entries. If an entry's timer is expired, then the + * uniarp old-age timeout function will be called for that entry. + * + * Called at splnet. + * + * Arguments: + * tip pointer to uniarp aging timer control block + * + * Returns: + * none + * + */ +void +uniarp_aging(tip) + struct atm_time *tip; +{ + struct uniarp *uap, *unext; + int i; + + + /* + * Schedule next timeout + */ + atm_timeout(&uniarp_timer, UNIARP_AGING, uniarp_aging); + + /* + * Run through arp table bumping each entry's aging timer. + * If an expired timer is found, process that entry. + */ + for (i = 0; i < UNIARP_HASHSIZ; i++) { + for (uap = uniarp_arptab[i]; uap; uap = unext) { + unext = uap->ua_next; + + if (uap->ua_aging && --uap->ua_aging == 0) + uniarp_svc_oldage(uap); + } + } + + /* + * Check out PVC aging timers too + */ + for (uap = uniarp_pvctab; uap; uap = unext) { + unext = uap->ua_next; + + if (uap->ua_aging && --uap->ua_aging == 0) + uniarp_pvc_oldage(uap); + } + + /* + * Only fully resolved SVC entries need aging, so there's no need + * to examine the 'no map' table + */ +} + diff --git a/sys/netatm/uni/uniarp_vcm.c b/sys/netatm/uni/uniarp_vcm.c new file mode 100644 index 0000000..9b1f211 --- /dev/null +++ b/sys/netatm/uni/uniarp_vcm.c @@ -0,0 +1,708 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: uniarp_vcm.c,v 1.10 1998/06/29 22:15:46 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * UNI ATMARP support (RFC1577) - Virtual Channel Management + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: uniarp_vcm.c,v 1.10 1998/06/29 22:15:46 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/uniip_var.h> + + +/* + * Local variables + */ +static struct attr_llc uniarp_llc = { + T_ATM_PRESENT, + { + T_ATM_LLC_SHARING, + 8, + {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00, 0x08, 0x06} + } +}; + +static struct t_atm_cause uniarp_cause = { + T_ATM_ITU_CODING, + T_ATM_LOC_USER, + T_ATM_CAUSE_TEMPORARY_FAILURE, + {0, 0, 0, 0} +}; + + +/* + * Process a new PVC requiring ATMARP support + * + * This function is called after IP/ATM has successfully opened a PVC which + * requires ATMARP support. We will send an InATMARP request over the PVC + * to elicit a response from the PVC's ATMARP peer informing us of its + * network address. This information will also be used by IP/ATM in order + * to complete its address-to-VC mapping table. + * + * Arguments: + * ivp pointer to PVC's IPVCC control block + * + * Returns: + * MAP_PROCEEDING - OK so far, querying for peer's mapping + * MAP_FAILED - error, unable to allocate resources + * + */ +int +uniarp_pvcopen(ivp) + struct ipvcc *ivp; +{ + struct uniip *uip; + struct uniarp *uap; + int s, err; + + ATM_DEBUG1("uniarp_pvcopen: ivp=0x%x\n", (int)ivp); + + ivp->iv_arpent = NULL; + + /* + * Check things out + */ + if ((ivp->iv_flags & IVF_LLC) == 0) + return (MAP_FAILED); + + /* + * Get uni interface + */ + uip = (struct uniip *)ivp->iv_ipnif->inf_isintf; + if (uip == NULL) + return (MAP_FAILED); + + /* + * Get an arp map entry + */ + uap = (struct uniarp *)atm_allocate(&uniarp_pool); + if (uap == NULL) + return (MAP_FAILED); + + /* + * Create our CM connection + */ + err = atm_cm_addllc(&uniarp_endpt, ivp, &uniarp_llc, + ivp->iv_conn, &ivp->iv_arpconn); + if (err) { + /* + * We don't take no (or maybe) for an answer + */ + if (ivp->iv_arpconn) { + (void) atm_cm_release(ivp->iv_arpconn, &uniarp_cause); + ivp->iv_arpconn = NULL; + } + atm_free((caddr_t)uap); + return (MAP_FAILED); + } + + /* + * Get map entry set up + */ + s = splnet(); + uap->ua_dstatm.address_format = T_ATM_ABSENT; + uap->ua_dstatmsub.address_format = T_ATM_ABSENT; + uap->ua_intf = uip; + + /* + * Put ivp on arp entry chain + */ + LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)uap; + + /* + * Put arp entry on pvc chain + */ + LINK2TAIL(uap, struct uniarp, uniarp_pvctab, ua_next); + + /* + * Send Inverse ATMARP request + */ + (void) uniarp_inarp_req(uip, &uap->ua_dstatm, &uap->ua_dstatmsub, ivp); + + /* + * Start resend timer + */ + uap->ua_aging = UNIARP_REVALID_AGE; + + (void) splx(s); + return (MAP_PROCEEDING); +} + + +/* + * Process a new outgoing SVC requiring ATMARP support + * + * This function is called by the IP/ATM module to resolve a destination + * IP address to an ATM address in order to open an SVC to that destination. + * If a valid mapping is already in our cache, then we just tell the caller + * about it and that's that. Otherwise, we have to allocate a new arp entry + * and issue a query for the mapping. + * + * Arguments: + * ivp pointer to SVC's IPVCC control block + * dst pointer to destination IP address + * + * Returns: + * MAP_VALID - Got the answer, returned via iv_arpent field. + * MAP_PROCEEDING - OK so far, querying for peer's mapping + * MAP_FAILED - error, unable to allocate resources + * + */ +int +uniarp_svcout(ivp, dst) + struct ipvcc *ivp; + struct in_addr *dst; +{ + struct uniip *uip; + struct uniarp *uap; + int s = splnet(); + + ATM_DEBUG2("uniarp_svcout: ivp=0x%x,dst=0x%x\n", (int)ivp, dst->s_addr); + + ivp->iv_arpent = NULL; + + /* + * Get uni interface + */ + uip = (struct uniip *)ivp->iv_ipnif->inf_isintf; + if (uip == NULL) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Lookup IP destination address + */ + UNIARP_LOOKUP(dst->s_addr, uap); + + if (uap) { + /* + * We've got an entry, verify interface + */ + if (uap->ua_intf != uip) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Chain this vcc onto entry + */ + LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)uap; + uap->ua_flags |= UAF_USED; + + if (uap->ua_flags & UAF_VALID) { + /* + * Entry is valid, we're done + */ + (void) splx(s); + return (MAP_VALID); + } else { + /* + * We're already looking for this address + */ + (void) splx(s); + return (MAP_PROCEEDING); + } + } + + /* + * No info in the cache. If we're the server, then + * we're already authoritative, so just deny request. + * If we're a client but the server VCC isn't open we + * also deny the request. + */ + if (uip->uip_arpstate != UIAS_CLIENT_ACTIVE) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * We're a client with an open VCC to the server, get a new arp entry + */ + uap = (struct uniarp *)atm_allocate(&uniarp_pool); + if (uap == NULL) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Get entry set up + */ + uap->ua_dstip.s_addr = dst->s_addr; + uap->ua_dstatm.address_format = T_ATM_ABSENT; + uap->ua_dstatm.address_length = 0; + uap->ua_dstatmsub.address_format = T_ATM_ABSENT; + uap->ua_dstatmsub.address_length = 0; + uap->ua_intf = uip; + + /* + * Link ipvcc to arp entry for later notification + */ + LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)uap; + uap->ua_flags |= UAF_USED; + + /* + * Add arp entry to table + */ + UNIARP_ADD(uap); + + /* + * Issue arp request for this address + */ + (void) uniarp_arp_req(uip, dst); + + /* + * Start retry timer + */ + UNIARP_TIMER(uap, UNIARP_ARP_RETRY); + + (void) splx(s); + return (MAP_PROCEEDING); +} + + +/* + * Process a new incoming SVC requiring ATMARP support + * + * This function is called by the IP/ATM module to resolve a caller's ATM + * address to its IP address for an incoming call in order to allow a + * bi-directional flow of IP packets on the SVC. If a valid mapping is + * already in our cache, then we will use it. Otherwise, we have to allocate + * a new arp entry and wait for the SVC to become active so that we can issue + * an InATMARP to the peer. + * + * Arguments: + * ivp pointer to SVC's IPVCC control block + * dst pointer to caller's ATM address + * dstsub pointer to caller's ATM subaddress + * + * Returns: + * MAP_VALID - Got the answer, returned via iv_arpent field. + * MAP_PROCEEDING - OK so far, querying for peer's mapping + * MAP_FAILED - error, unable to allocate resources + * + */ +int +uniarp_svcin(ivp, dst, dstsub) + struct ipvcc *ivp; + Atm_addr *dst; + Atm_addr *dstsub; +{ + struct uniip *uip; + struct uniarp *uap; + int found = 0, i, s = splnet(); + + ATM_DEBUG1("uniarp_svcin: ivp=0x%x\n", (int)ivp); + + /* + * Clear ARP entry field + */ + ivp->iv_arpent = NULL; + + /* + * Check things out + */ + if ((ivp->iv_flags & IVF_LLC) == 0) + return (MAP_FAILED); + + /* + * Get uni interface + */ + uip = (struct uniip *)ivp->iv_ipnif->inf_isintf; + if (uip == NULL) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Make sure we're configured as a client or server + */ + if (uip->uip_arpstate == UIAS_NOTCONF) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * If we know the caller's ATM address, look it up + */ + uap = NULL; + if (dst->address_format != T_ATM_ABSENT) { + for (i = 0; (i < UNIARP_HASHSIZ) && (found == 0); i++) { + for (uap = uniarp_arptab[i]; uap; uap = uap->ua_next) { + if (ATM_ADDR_EQUAL(dst, &uap->ua_dstatm) && + ATM_ADDR_EQUAL(dstsub, &uap->ua_dstatmsub)){ + found = 1; + break; + } + } + } + if (uap == NULL) { + for (uap = uniarp_nomaptab; uap; uap = uap->ua_next) { + if (ATM_ADDR_EQUAL(dst, &uap->ua_dstatm) && + ATM_ADDR_EQUAL(dstsub, &uap->ua_dstatmsub)) + break; + } + } + } + + if (uap) { + /* + * We've got an entry, verify interface + */ + if (uap->ua_intf != uip) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Chain the vcc onto this entry + */ + LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)uap; + uap->ua_flags |= UAF_USED; + + if (uap->ua_flags & UAF_VALID) { + /* + * Entry is valid, we're done + */ + (void) splx(s); + return (MAP_VALID); + } else { + /* + * We're already looking for this address + */ + (void) splx(s); + return (MAP_PROCEEDING); + } + } + + /* + * No info in the cache - get a new arp entry + */ + uap = (struct uniarp *)atm_allocate(&uniarp_pool); + if (uap == NULL) { + (void) splx(s); + return (MAP_FAILED); + } + + /* + * Get entry set up + */ + ATM_ADDR_COPY(dst, &uap->ua_dstatm); + ATM_ADDR_COPY(dstsub, &uap->ua_dstatmsub); + uap->ua_intf = uip; + + /* + * Link ipvcc to arp entry for later notification + */ + LINK2TAIL(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + ivp->iv_arpent = (struct arpmap *)uap; + uap->ua_flags |= UAF_USED; + + /* + * Add arp entry to 'nomap' table + */ + LINK2TAIL(uap, struct uniarp, uniarp_nomaptab, ua_next); + + (void) splx(s); + + /* + * Now we just wait for SVC to become active + */ + return (MAP_PROCEEDING); +} + + +/* + * Process ARP SVC activation notification + * + * This function is called by the IP/ATM module whenever a previously + * opened SVC has successfully been connected. + * + * Arguments: + * ivp pointer to SVC's IPVCC control block + * + * Returns: + * 0 activation processing successful + * errno activation failed - reason indicated + * + */ +int +uniarp_svcactive(ivp) + struct ipvcc *ivp; +{ + struct ip_nif *inp; + struct uniip *uip; + struct uniarp *uap; + int err, s = splnet(); + + ATM_DEBUG1("uniarp_svcactive: ivp=0x%x\n", (int)ivp); + + inp = ivp->iv_ipnif; + uip = (struct uniip *)inp->inf_isintf; + uap = (struct uniarp *)ivp->iv_arpent; + + /* + * First, we need to create our CM connection + */ + err = atm_cm_addllc(&uniarp_endpt, ivp, &uniarp_llc, + ivp->iv_conn, &ivp->iv_arpconn); + if (err) { + /* + * We don't take no (or maybe) for an answer + */ + if (ivp->iv_arpconn) { + (void) atm_cm_release(ivp->iv_arpconn, &uniarp_cause); + ivp->iv_arpconn = NULL; + } + return (err); + } + + /* + * Is this the client->server vcc?? + */ + if (uip->uip_arpsvrvcc == ivp) { + + /* + * Yep, go into the client registration phase + */ + uip->uip_arpstate = UIAS_CLIENT_REGISTER; + + /* + * To register ourselves, RFC1577 says we should wait + * around for the server to send us an InATMARP_Request. + * However, draft-1577+ just has us send an ATMARP_Request + * for our own address. To keep everyone happy, we'll go + * with both and see what works! + */ + (void) uniarp_arp_req(uip, &(IA_SIN(inp->inf_addr)->sin_addr)); + + /* + * Start retry timer + */ + UNIIP_ARP_TIMER(uip, 1 * ATM_HZ); + + (void) splx(s); + return (0); + } + + /* + * Send an InATMARP_Request on this VCC to find out/notify who's at + * the other end. If we're the server, this will start off the + * RFC1577 registration procedure. If we're a client, then this + * SVC is for user data and it's pretty likely that both ends are + * going to be sending packets. So, if we're the caller, we'll be + * nice and let the callee know right away who we are. If we're the + * callee, let's find out asap the caller's IP address. + */ + (void) uniarp_inarp_req(uip, &uap->ua_dstatm, &uap->ua_dstatmsub, ivp); + + /* + * Start retry timer if entry isn't valid yet + */ + if (((uap->ua_flags & UAF_VALID) == 0) && + ((uap->ua_time.ti_flag & TIF_QUEUED) == 0)) + UNIARP_TIMER(uap, UNIARP_ARP_RETRY); + + (void) splx(s); + return (0); +} + + +/* + * Process VCC close + * + * This function is called just prior to IP/ATM closing a VCC which + * supports ATMARP. We'll sever our links to the VCC and then + * figure out how much more cleanup we need to do for now. + * + * Arguments: + * ivp pointer to VCC's IPVCC control block + * + * Returns: + * none + * + */ +void +uniarp_vcclose(ivp) + struct ipvcc *ivp; +{ + struct uniip *uip; + struct uniarp *uap; + int s; + + ATM_DEBUG1("uniarp_vcclose: ivp=0x%x\n", (int)ivp); + + /* + * Close our CM connection + */ + if (ivp->iv_arpconn) { + (void) atm_cm_release(ivp->iv_arpconn, &uniarp_cause); + ivp->iv_arpconn = NULL; + } + + /* + * Get atmarp entry + */ + if ((uap = (struct uniarp *)ivp->iv_arpent) == NULL) + return; + uip = uap->ua_intf; + + s = splnet(); + + /* + * If this is the arpserver VCC, then schedule ourselves to + * reopen the connection soon + */ + if (uip->uip_arpsvrvcc == ivp) { + uip->uip_arpsvrvcc = NULL; + uip->uip_arpstate = UIAS_CLIENT_POPEN; + UNIIP_ARP_CANCEL(uip); + UNIIP_ARP_TIMER(uip, 5 * ATM_HZ); + } + + /* + * Remove IP VCC from chain + */ + UNLINK(ivp, struct ipvcc, uap->ua_ivp, iv_arpnext); + + /* + * SVCs and PVCs are handled separately + */ + if (ivp->iv_flags & IVF_SVC) { + /* + * If the mapping is currently valid or in use, or if there + * are other VCCs still using this mapping, we're done for now + */ + if ((uap->ua_flags & (UAF_VALID | UAF_LOCKED)) || + (uap->ua_origin >= UAO_PERM) || + (uap->ua_ivp != NULL)) { + (void) splx(s); + return; + } + + /* + * Unlink the entry + */ + if (uap->ua_dstip.s_addr == 0) { + UNLINK(uap, struct uniarp, uniarp_nomaptab, ua_next); + } else { + UNIARP_DELETE(uap); + } + } else { + /* + * Remove entry from pvc table + */ + UNLINK(uap, struct uniarp, uniarp_pvctab, ua_next); + } + + UNIARP_CANCEL(uap); + + /* + * Finally, free the entry + */ + atm_free((caddr_t)uap); + + (void) splx(s); + return; +} + + +/* + * Process ATMARP VCC Connected Notification + * + * Arguments: + * toku owner's connection token (ipvcc protocol block) + * + * Returns: + * none + * + */ +void +uniarp_connected(toku) + void *toku; +{ + + /* + * Since we only do atm_cm_addllc()'s on active connections, + * we should never get called here... + */ + panic("uniarp_connected"); +} + + +/* + * Process ATMARP VCC Cleared Notification + * + * Arguments: + * toku owner's connection token (ipvcc protocol block) + * cause pointer to cause code + * + * Returns: + * none + * + */ +void +uniarp_cleared(toku, cause) + void *toku; + struct t_atm_cause *cause; +{ + struct ipvcc *ivp = toku; + int s; + + s = splnet(); + + /* + * We're done with VCC + */ + ivp->iv_arpconn = NULL; + + /* + * If IP is finished with VCC, then we'll free it + */ + if (ivp->iv_state == IPVCC_FREE) + atm_free((caddr_t)ivp); + + (void) splx(s); +} + diff --git a/sys/netatm/uni/uniip.c b/sys/netatm/uni/uniip.c new file mode 100644 index 0000000..0039585 --- /dev/null +++ b/sys/netatm/uni/uniip.c @@ -0,0 +1,252 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: uniip.c,v 1.6 1998/05/18 19:18:42 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * UNI IP interface module + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: uniip.c,v 1.6 1998/05/18 19:18:42 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include <netatm/uni/uniip_var.h> + + +/* + * Local functions + */ +static int uniip_ipact __P((struct ip_nif *)); +static int uniip_ipdact __P((struct ip_nif *)); + + +/* + * Global variables + */ +struct uniip *uniip_head = NULL; + +struct ip_serv uniip_ipserv = { + uniip_ipact, + uniip_ipdact, + uniarp_ioctl, + uniarp_pvcopen, + uniarp_svcout, + uniarp_svcin, + uniarp_svcactive, + uniarp_vcclose, + NULL, + {ATM_AAL5, ATM_ENC_LLC}, +}; + + +/* + * Local variables + */ +static struct sp_info uniip_pool = { + "uni ip pool", /* si_name */ + sizeof(struct uniip), /* si_blksiz */ + 2, /* si_blkcnt */ + 100 /* si_maxallow */ +}; + + +/* + * Process module loading notification + * + * Called whenever the uni module is initializing. + * + * Arguments: + * none + * + * Returns: + * 0 initialization successful + * errno initialization failed - reason indicated + * + */ +int +uniip_start() +{ + int err; + + /* + * Tell arp to initialize stuff + */ + err = uniarp_start(); + + return (err); +} + + +/* + * Process module unloading notification + * + * Called whenever the uni module is about to be unloaded. All signalling + * instances will have been previously detached. All uniip resources + * must be freed now. + * + * Arguments: + * none + * + * Returns: + * 0 shutdown was successful + * errno shutdown failed - reason indicated + * + */ +int +uniip_stop() +{ + + /* + * All IP interfaces should be gone + */ + if (uniip_head) + return (EBUSY); + + /* + * Tell arp to stop + */ + uniarp_stop(); + + /* + * Free our storage pools + */ + atm_release_pool(&uniip_pool); + + return (0); +} + + +/* + * Process IP Network Interface Activation + * + * Called whenever an IP network interface becomes active. + * + * Called at splnet. + * + * Arguments: + * inp pointer to IP network interface + * + * Returns: + * 0 command successful + * errno command failed - reason indicated + * + */ +static int +uniip_ipact(inp) + struct ip_nif *inp; +{ + struct uniip *uip; + + /* + * Make sure we don't already have this interface + */ + for (uip = uniip_head; uip; uip = uip->uip_next) { + if (uip->uip_ipnif == inp) + return (EEXIST); + } + + /* + * Get a new interface control block + */ + uip = (struct uniip *)atm_allocate(&uniip_pool); + if (uip == NULL) + return (ENOMEM); + + /* + * Initialize and link up + */ + uip->uip_ipnif = inp; + LINK2TAIL(uip, struct uniip, uniip_head, uip_next); + + /* + * Link from IP world + */ + inp->inf_isintf = (caddr_t)uip; + + /* + * Tell arp about new interface + */ + uniarp_ipact(uip); + + return (0); +} + + +/* + * Process IP Network Interface Deactivation + * + * Called whenever an IP network interface becomes inactive. + * + * Called at splnet. + * + * Arguments: + * inp pointer to IP network interface + * + * Returns: + * 0 command successful + * errno command failed - reason indicated + * + */ +static int +uniip_ipdact(inp) + struct ip_nif *inp; +{ + struct uniip *uip; + + /* + * Get the appropriate IP interface block + */ + uip = (struct uniip *)inp->inf_isintf; + if (uip == NULL) + return (ENXIO); + + /* + * Let arp know about this + */ + uniarp_ipdact(uip); + + /* + * Free interface info + */ + UNLINK(uip, struct uniip, uniip_head, uip_next); + if (uip->uip_prefix != NULL) + KM_FREE(uip->uip_prefix, + uip->uip_nprefix * sizeof(struct uniarp_prf), M_DEVBUF); + atm_free((caddr_t)uip); + + return (0); +} + diff --git a/sys/netatm/uni/uniip_var.h b/sys/netatm/uni/uniip_var.h new file mode 100644 index 0000000..ea1eb8c --- /dev/null +++ b/sys/netatm/uni/uniip_var.h @@ -0,0 +1,318 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: uniip_var.h,v 1.9 1998/07/13 00:00:39 mks Exp $ + * + */ + +/* + * ATM Forum UNI Support + * --------------------- + * + * IP interface control blocks + * + */ + +#ifndef _UNI_UNIIP_VAR_H +#define _UNI_UNIIP_VAR_H + +#ifdef ATM_KERNEL +/* + * UNI IP network interface structure. There will be one such structure for + * each IP network interface attached via a UNI signalling instance. + */ +struct uniip { + struct uniip *uip_next; /* Next attached IP interface */ + struct ip_nif *uip_ipnif; /* IP network interface */ + u_char uip_flags; /* Interface flags (see below) */ + + /* ATMARP (RFC1577) */ + u_char uip_arpstate; /* ARP interface state (see below) */ + struct arpmap uip_arpsvrmap; /* ATMARP server map info */ + struct ipvcc *uip_arpsvrvcc; /* ATMARP server's VCC */ + int uip_nprefix; /* Count of IP prefixes (server only) */ + struct uniarp_prf *uip_prefix; /* Array of IP prefixes (server only) */ + struct atm_time uip_arptime; /* ARP timer controls */ +}; +#define uip_arpsvrip uip_arpsvrmap.am_dstip +#define uip_arpsvratm uip_arpsvrmap.am_dstatm +#define uip_arpsvrsub uip_arpsvrmap.am_dstatmsub +#endif /* ATM_KERNEL */ + +/* + * UNI Interface Flags + */ +#define UIF_IFADDR 0x01 /* Interface address is set */ + +/* + * UNI ARP Interface States + */ +#define UIAS_NOTCONF 1 /* Not configured */ +#define UIAS_SERVER_ACTIVE 2 /* Server - active */ +#define UIAS_CLIENT_PADDR 3 /* Client - pending ATM address */ +#define UIAS_CLIENT_POPEN 4 /* Client - pending server vcc open */ +#define UIAS_CLIENT_REGISTER 5 /* Client - registering with server */ +#define UIAS_CLIENT_ACTIVE 6 /* Client - active */ + + +#ifdef ATM_KERNEL +/* + * Structure for allowable IP prefixes for ATMARP server registration + */ +struct uniarp_prf { + struct in_addr upf_addr; /* Prefix address */ + struct in_addr upf_mask; /* Prefix mask */ +}; + + +/* + * UNI ARP protocol constants + */ +#define UNIARP_AGING (60 * ATM_HZ) /* Aging timer tick */ +#define UNIARP_HASHSIZ 19 /* Hash table size */ +#define UNIARP_REGIS_REFRESH (15 * 60 * ATM_HZ) + /* Client registration refresh timer */ +#define UNIARP_REGIS_RETRY (60 * ATM_HZ) + /* Client registration retry timer */ +#define UNIARP_ARP_RETRY (3 * ATM_HZ) /* ARP command retry timer */ +#define UNIARP_CLIENT_AGE 12 /* Client validation timeout */ +#define UNIARP_CLIENT_RETRY 3 /* Client validation retrys */ +#define UNIARP_SERVER_AGE 17 /* Server validation timeout */ +#define UNIARP_SERVER_RETRY 3 /* Server validation retrys */ +#define UNIARP_RETRY_AGE 1 /* Retry timeout */ +#define UNIARP_REVALID_AGE 2 /* Revalidation timeout */ +#define UNIARP_MIN_REFRESH 10 /* Minimum entry refresh time */ + + +/* + * Structure for ATMARP mappings. Each of these structures will contain + * IP address to ATM hardware address mappings. There will be one such + * structure for each IP address and for each unresolved ATM address + * currently in use. + */ +struct uniarp { + struct arpmap ua_arpmap; /* Common entry header */ + struct uniip *ua_intf; /* Interface where we learned answer */ + struct uniarp *ua_next; /* Hash chain link */ + u_char ua_flags; /* Flags (see below) */ + u_char ua_origin; /* Source of mapping (see below) */ + u_char ua_retry; /* Retry counter */ + u_char ua_aging; /* Aging timeout value (minutes) */ + struct ipvcc *ua_ivp; /* Head of IP VCC chain */ + struct atm_time ua_time; /* Timer controls */ +}; +#define ua_dstip ua_arpmap.am_dstip +#define ua_dstatm ua_arpmap.am_dstatm +#define ua_dstatmsub ua_arpmap.am_dstatmsub +#endif /* ATM_KERNEL */ + +/* + * UNIARP Entry Flags + */ +#define UAF_VALID ARPF_VALID /* Entry is valid */ +#define UAF_REFRESH ARPF_REFRESH /* Entry has been refreshed */ +#define UAF_LOCKED 0x04 /* Entry is locked */ +#define UAF_USED 0x08 /* Entry has been used recently */ + +/* + * UNIARP Entry Origin + * + * The origin values are ranked according to the source precedence. + * Larger values are more preferred. + */ +#define UAO_LOCAL 100 /* Local address */ +#define UAO_PERM ARP_ORIG_PERM /* Permanently installed */ +#define UAO_REGISTER 40 /* Learned via client registration */ +#define UAO_SCSP 30 /* Learned via SCSP */ +#define UAO_LOOKUP 20 /* Learned via server lookup */ +#define UAO_PEER_RSP 15 /* Learned from peer - inarp rsp */ +#define UAO_PEER_REQ 10 /* Learned from peer - inarp req */ + +/* + * ATMARP/InATMARP Packet Format + */ +struct atmarp_hdr { + u_short ah_hrd; /* Hardware type (see below) */ + u_short ah_pro; /* Protocol type */ + u_char ah_shtl; /* Type/len of source ATM address */ + u_char ah_sstl; /* Type/len of source ATM subaddress */ + u_short ah_op; /* Operation code (see below) */ + u_char ah_spln; /* Length of source protocol address */ + u_char ah_thtl; /* Type/len of target ATM address */ + u_char ah_tstl; /* Type/len of target ATM subaddress */ + u_char ah_tpln; /* Length of target protocol address */ +#ifdef notdef + /* Variable size fields */ + u_char ah_sha[]; /* Source ATM address */ + u_char ah_ssa[]; /* Source ATM subaddress */ + u_char ah_spa[]; /* Source protocol address */ + u_char ah_tha[]; /* Target ATM subaddress */ + u_char ah_tsa[]; /* Target ATM address */ + u_char ah_tpa[]; /* Target protocol subaddress */ +#endif +}; + +/* + * Hardware types + */ +#define ARP_ATMFORUM 19 + +/* + * Operation types + */ +#define ARP_REQUEST 1 /* ATMARP request */ +#define ARP_REPLY 2 /* ATMARP response */ +#define INARP_REQUEST 8 /* InATMARP request */ +#define INARP_REPLY 9 /* InATMARP response */ +#define ARP_NAK 10 /* ATMARP negative ack */ + +/* + * Type/length fields + */ +#define ARP_TL_TMASK 0x40 /* Type mask */ +#define ARP_TL_NSAPA 0x00 /* Type = ATM Forum NSAPA */ +#define ARP_TL_E164 0x40 /* Type = E.164 */ +#define ARP_TL_LMASK 0x3f /* Length mask */ + + +#ifdef ATM_KERNEL +/* + * Timer macros + */ +#define UNIIP_ARP_TIMER(s, t) atm_timeout(&(s)->uip_arptime, (t), uniarp_iftimeout) +#define UNIIP_ARP_CANCEL(s) atm_untimeout(&(s)->uip_arptime) +#define UNIARP_TIMER(s, t) atm_timeout(&(s)->ua_time, (t), uniarp_timeout) +#define UNIARP_CANCEL(s) atm_untimeout(&(s)->ua_time) + + +/* + * Macros for manipulating UNIARP tables and entries + */ +#define UNIARP_HASH(ip) ((u_long)(ip) % UNIARP_HASHSIZ) + +#define UNIARP_ADD(ua) \ +{ \ + struct uniarp **h; \ + h = &uniarp_arptab[UNIARP_HASH((ua)->ua_dstip.s_addr)]; \ + LINK2TAIL((ua), struct uniarp, *h, ua_next); \ +} + +#define UNIARP_DELETE(ua) \ +{ \ + struct uniarp **h; \ + h = &uniarp_arptab[UNIARP_HASH((ua)->ua_dstip.s_addr)]; \ + UNLINK((ua), struct uniarp, *h, ua_next); \ +} + +#define UNIARP_LOOKUP(ip, ua) \ +{ \ + for ((ua) = uniarp_arptab[UNIARP_HASH(ip)]; \ + (ua); (ua) = (ua)->ua_next) { \ + if ((ua)->ua_dstip.s_addr == (ip)) \ + break; \ + } \ +} + + +/* + * Global UNIARP Statistics + */ +struct uniarp_stat { + u_long uas_rcvdrop; /* Input packets dropped */ +}; + + +/* + * External variables + */ +extern struct uniip *uniip_head; +extern struct ip_serv uniip_ipserv; +extern struct uniarp *uniarp_arptab[]; +extern struct uniarp *uniarp_nomaptab; +extern struct uniarp *uniarp_pvctab; +extern struct sp_info uniarp_pool; +extern struct atm_time uniarp_timer; +extern int uniarp_print; +extern Atm_endpoint uniarp_endpt; +extern struct uniarp_stat uniarp_stat; + + +/* + * Global function declarations + */ + /* uniarp.c */ +int uniarp_start __P((void)); +void uniarp_stop __P((void)); +void uniarp_ipact __P((struct uniip *)); +void uniarp_ipdact __P((struct uniip *)); +void uniarp_ifaddr __P((struct siginst *)); +void uniarp_iftimeout __P((struct atm_time *)); +int uniarp_ioctl __P((int, caddr_t, caddr_t)); +caddr_t uniarp_getname __P((void *)); + + /* uniarp_cache.c */ +int uniarp_cache_svc __P((struct uniip *, struct in_addr *, + Atm_addr *, Atm_addr *, u_int)); +void uniarp_cache_pvc __P((struct ipvcc *, struct in_addr *, + Atm_addr *, Atm_addr *)); +int uniarp_validate_ip __P((struct uniip *, struct in_addr *, + u_int)); + + /* uniarp_input.c */ +void uniarp_cpcs_data __P((void *, KBuffer *)); +void uniarp_pdu_print __P((struct ipvcc *, KBuffer *, char *)); + + /* uniarp_output.c */ +int uniarp_arp_req __P((struct uniip *, struct in_addr *)); +int uniarp_arp_rsp __P((struct uniip *, struct arpmap *, + struct in_addr *, Atm_addr *, + Atm_addr *, struct ipvcc *)); +int uniarp_arp_nak __P((struct uniip *, KBuffer *, struct ipvcc *)); +int uniarp_inarp_req __P((struct uniip *, Atm_addr *, + Atm_addr *, struct ipvcc *)); +int uniarp_inarp_rsp __P((struct uniip *, struct in_addr *, + Atm_addr *, Atm_addr *, struct ipvcc *)); + + /* uniarp_timer.c */ +void uniarp_timeout __P((struct atm_time *)); +void uniarp_aging __P((struct atm_time *)); + + /* uniarp_vcm.c */ +int uniarp_pvcopen __P((struct ipvcc *)); +int uniarp_svcout __P((struct ipvcc *, struct in_addr *)); +int uniarp_svcin __P((struct ipvcc *, Atm_addr *, Atm_addr *)); +int uniarp_svcactive __P((struct ipvcc *)); +void uniarp_vcclose __P((struct ipvcc *)); +void uniarp_connected __P((void *)); +void uniarp_cleared __P((void *, struct t_atm_cause *)); + + /* uniip.c */ +int uniip_start __P((void)); +int uniip_stop __P((void)); + + +#endif /* ATM_KERNEL */ + +#endif /* _UNI_UNIIP_VAR_H */ diff --git a/sys/netatm/uni/unisig.h b/sys/netatm/uni/unisig.h new file mode 100644 index 0000000..b69714d --- /dev/null +++ b/sys/netatm/uni/unisig.h @@ -0,0 +1,49 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: unisig.h,v 1.2 1997/05/06 22:21:33 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Protocol control blocks + * + */ + +#ifndef _UNISIG_H +#define _UNISIG_H + +/* + * ATM Forum UNI 3.0/3.1 Signalling + */ +#define UNISIG_SIG_VPI 0 /* Signalling VPI */ +#define UNISIG_SIG_VCI 5 /* Signalling VCI */ + +#define STACK_SSCF "uni_sscf" + +#endif /* _UNISIG_H */ diff --git a/sys/netatm/uni/unisig_decode.c b/sys/netatm/uni/unisig_decode.c new file mode 100644 index 0000000..98f5dfd --- /dev/null +++ b/sys/netatm/uni/unisig_decode.c @@ -0,0 +1,2474 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: unisig_decode.c,v 1.13 1998/08/26 23:29:20 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Message formatting module + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_decode.c,v 1.13 1998/08/26 23:29:20 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/unisig.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/unisig_msg.h> +#include <netatm/uni/unisig_mbuf.h> +#include <netatm/uni/unisig_decode.h> + +#define ALLOC_IE(ie) \ + (ie) = (struct ie_generic *) atm_allocate(&unisig_iepool); \ + if (!ie) \ + return(ENOMEM); + + +/* + * Local functions + */ +static int usf_dec_ie __P((struct usfmt *, struct unisig_msg *, struct ie_generic *)); +static int usf_dec_ie_hdr __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_aalp __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_clrt __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_bbcp __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_bhli __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_blli __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_clst __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_cdad __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_cdsa __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_cgad __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_cgsa __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_caus __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_cnid __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_qosp __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_brpi __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_rsti __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_bsdc __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_trnt __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_uimp __P((struct usfmt *, struct ie_generic *)); +static int usf_dec_ie_ident __P((struct usfmt *, struct ie_generic *, + struct ie_decode_tbl *)); +static int usf_dec_atm_addr __P((struct usfmt *, Atm_addr *, int)); + + +/* + * Table associating IE type with IE vector index + */ +u_char unisig_ie_ident_vec[] = { + UNI_IE_AALP, + UNI_IE_CLRT, + UNI_IE_BBCP, + UNI_IE_BHLI, + UNI_IE_BLLI, + UNI_IE_CLST, + UNI_IE_CDAD, + UNI_IE_CDSA, + UNI_IE_CGAD, + UNI_IE_CGSA, + UNI_IE_CAUS, + UNI_IE_CNID, + UNI_IE_QOSP, + UNI_IE_BRPI, + UNI_IE_RSTI, + UNI_IE_BLSH, + UNI_IE_BNSH, + UNI_IE_BSDC, + UNI_IE_TRNT, + UNI_IE_EPRF, + UNI_IE_EPST +}; + + +/* + * Tables specifying which IEs are mandatory, optional, and + * not allowed for each Q.2931 message type + */ +static u_char uni_calp_ie_tbl[] = { + IE_NA, /* ATM AAL Parameters */ + IE_NA, /* ATM User Cell Rate */ + IE_NA, /* Broadband Bearer Capability */ + IE_NA, /* Broadband High Layer Information */ + IE_NA, /* Broadband Low Layer Information */ + IE_NA, /* Call State */ + IE_NA, /* Called Party Number */ + IE_NA, /* Called Party Subaddress */ + IE_NA, /* Calling Party Number */ + IE_NA, /* Calling Party Subaddress */ + IE_NA, /* Cause */ + IE_OPT, /* Connection Identifier */ + IE_NA, /* Quality of Service Parameters */ + IE_NA, /* Broadband Repeat Indicator */ + IE_NA, /* Restart Indicator */ + IE_NA, /* Broadband Locking Shift */ + IE_NA, /* Broadband Non-locking Shift */ + IE_NA, /* Broadband Sending Complete */ + IE_NA, /* Transit Net */ + IE_OPT, /* Endpoint Reference */ + IE_NA /* Endpoint State */ +}; + +static u_char uni_conn_ie_tbl[] = { + IE_OPT, /* ATM AAL Parameters */ + IE_NA, /* ATM User Cell Rate */ + IE_NA, /* Broadband Bearer Capability */ + IE_NA, /* Broadband High Layer Information */ + IE_OPT, /* Broadband Low Layer Information */ + IE_NA, /* Call State */ + IE_NA, /* Called Party Number */ + IE_NA, /* Called Party Subaddress */ + IE_NA, /* Calling Party Number */ + IE_NA, /* Calling Party Subaddress */ + IE_NA, /* Cause */ + IE_OPT, /* Connection Identifier */ + IE_NA, /* Quality of Service Parameters */ + IE_NA, /* Broadband Repeat Indicator */ + IE_NA, /* Restart Indicator */ + IE_NA, /* Broadband Locking Shift */ + IE_NA, /* Broadband Non-locking Shift */ + IE_NA, /* Broadband Sending Complete */ + IE_NA, /* Transit Net */ + IE_OPT, /* Endpoint Reference */ + IE_NA /* Endpoint State */ +}; + +static u_char uni_cack_ie_tbl[] = { + IE_NA, /* ATM AAL Parameters */ + IE_NA, /* ATM User Cell Rate */ + IE_NA, /* Broadband Bearer Capability */ + IE_NA, /* Broadband High Layer Information */ + IE_NA, /* Broadband Low Layer Information */ + IE_NA, /* Call State */ + IE_NA, /* Called Party Number */ + IE_NA, /* Called Party Subaddress */ + IE_NA, /* Calling Party Number */ + IE_NA, /* Calling Party Subaddress */ + IE_NA, /* Cause */ + IE_NA, /* Connection Identifier */ + IE_NA, /* Quality of Service Parameters */ + IE_NA, /* Broadband Repeat Indicator */ + IE_NA, /* Restart Indicator */ + IE_NA, /* Broadband Locking Shift */ + IE_NA, /* Broadband Non-locking Shift */ + IE_NA, /* Broadband Sending Complete */ + IE_NA, /* Transit Net */ + IE_NA, /* Endpoint Reference */ + IE_NA /* Endpoint State */ +}; + +static u_char uni_setu_ie_tbl[] = { + IE_MAND, /* ATM AAL Parameters (not required by + UNI 3.0) */ + IE_MAND, /* ATM User Cell Rate */ + IE_MAND, /* Broadband Bearer Capability */ + IE_OPT, /* Broadband High Layer Information */ + IE_MAND, /* Broadband Low Layer Information (not required by UNI 3.0 */ + IE_NA, /* Call State */ + IE_MAND, /* Called Party Number */ + IE_OPT, /* Called Party Subaddress */ + IE_OPT, /* Calling Party Number */ + IE_OPT, /* Calling Party Subaddress */ + IE_NA, /* Cause */ + IE_MAND, /* Connection Identifier */ + IE_MAND, /* Quality of Service Parameters */ + IE_OPT, /* Broadband Repeat Indicator */ + IE_NA, /* Restart Indicator */ + IE_NA, /* Broadband Locking Shift */ + IE_NA, /* Broadband Non-locking Shift */ + IE_OPT, /* Broadband Sending Complete */ + IE_NA, /* Transit Net */ + IE_OPT, /* Endpoint Reference */ + IE_NA /* Endpoint State */ +}; + +static u_char uni_rlse_ie_tbl[] = { + IE_NA, /* ATM AAL Parameters */ + IE_NA, /* ATM User Cell Rate */ + IE_NA, /* Broadband Bearer Capability */ + IE_NA, /* Broadband High Layer Information */ + IE_NA, /* Broadband Low Layer Information */ + IE_NA, /* Call State */ + IE_NA, /* Called Party Number */ + IE_NA, /* Called Party Subaddress */ + IE_NA, /* Calling Party Number */ + IE_NA, /* Calling Party Subaddress */ + IE_MAND, /* Cause */ + IE_NA, /* Connection Identifier */ + IE_NA, /* Quality of Service Parameters */ + IE_NA, /* Broadband Repeat Indicator */ + IE_NA, /* Restart Indicator */ + IE_NA, /* Broadband Locking Shift */ + IE_NA, /* Broadband Non-locking Shift */ + IE_NA, /* Broadband Sending Complete */ + IE_NA, /* Transit Net */ + IE_NA, /* Endpoint Reference */ + IE_NA /* Endpoint State */ +}; + +static u_char uni_rlsc_ie_tbl[] = { + IE_NA, /* ATM AAL Parameters */ + IE_NA, /* ATM User Cell Rate */ + IE_NA, /* Broadband Bearer Capability */ + IE_NA, /* Broadband High Layer Information */ + IE_NA, /* Broadband Low Layer Information */ + IE_NA, /* Call State */ + IE_NA, /* Called Party Number */ + IE_NA, /* Called Party Subaddress */ + IE_NA, /* Calling Party Number */ + IE_NA, /* Calling Party Subaddress */ + IE_MAND, /* Cause */ + IE_NA, /* Connection Identifier */ + IE_NA, /* Quality of Service Parameters */ + IE_NA, /* Broadband Repeat Indicator */ + IE_NA, /* Restart Indicator */ + IE_NA, /* Broadband Locking Shift */ + IE_NA, /* Broadband Non-locking Shift */ + IE_NA, /* Broadband Sending Complete */ + IE_NA, /* Transit Net */ + IE_NA, /* Endpoint Reference */ + IE_NA /* Endpoint State */ +}; + +static u_char uni_rstr_ie_tbl[] = { + IE_NA, /* ATM AAL Parameters */ + IE_NA, /* ATM User Cell Rate */ + IE_NA, /* Broadband Bearer Capability */ + IE_NA, /* Broadband High Layer Information */ + IE_NA, /* Broadband Low Layer Information */ + IE_NA, /* Call State */ + IE_NA, /* Called Party Number */ + IE_NA, /* Called Party Subaddress */ + IE_NA, /* Calling Party Number */ + IE_NA, /* Calling Party Subaddress */ + IE_NA, /* Cause */ + IE_OPT, /* Connection Identifier */ + IE_NA, /* Quality of Service Parameters */ + IE_NA, /* Broadband Repeat Indicator */ + IE_MAND, /* Restart Indicator */ + IE_NA, /* Broadband Locking Shift */ + IE_NA, /* Broadband Non-locking Shift */ + IE_NA, /* Broadband Sending Complete */ + IE_NA, /* Transit Net */ + IE_NA, /* Endpoint Reference */ + IE_NA /* Endpoint State */ +}; + +static u_char uni_rsta_ie_tbl[] = { + IE_NA, /* ATM AAL Parameters */ + IE_NA, /* ATM User Cell Rate */ + IE_NA, /* Broadband Bearer Capability */ + IE_NA, /* Broadband High Layer Information */ + IE_NA, /* Broadband Low Layer Information */ + IE_NA, /* Call State */ + IE_NA, /* Called Party Number */ + IE_NA, /* Called Party Subaddress */ + IE_NA, /* Calling Party Number */ + IE_NA, /* Calling Party Subaddress */ + IE_NA, /* Cause */ + IE_OPT, /* Connection Identifier */ + IE_NA, /* Quality of Service Parameters */ + IE_NA, /* Broadband Repeat Indicator */ + IE_MAND, /* Restart Indicator */ + IE_NA, /* Broadband Locking Shift */ + IE_NA, /* Broadband Non-locking Shift */ + IE_NA, /* Broadband Sending Complete */ + IE_NA, /* Transit Net */ + IE_NA, /* Endpoint Reference */ + IE_NA /* Endpoint State */ +}; + +static u_char uni_stat_ie_tbl[] = { + IE_NA, /* ATM AAL Parameters */ + IE_NA, /* ATM User Cell Rate */ + IE_NA, /* Broadband Bearer Capability */ + IE_NA, /* Broadband High Layer Information */ + IE_NA, /* Broadband Low Layer Information */ + IE_MAND, /* Call State */ + IE_NA, /* Called Party Number */ + IE_NA, /* Called Party Subaddress */ + IE_NA, /* Calling Party Number */ + IE_NA, /* Calling Party Subaddress */ + IE_MAND, /* Cause */ + IE_NA, /* Connection Identifier */ + IE_NA, /* Quality of Service Parameters */ + IE_NA, /* Broadband Repeat Indicator */ + IE_NA, /* Restart Indicator */ + IE_NA, /* Broadband Locking Shift */ + IE_NA, /* Broadband Non-locking Shift */ + IE_NA, /* Broadband Sending Complete */ + IE_NA, /* Transit Net */ + IE_OPT, /* Endpoint Reference */ + IE_OPT /* Endpoint State */ +}; + +static u_char uni_senq_ie_tbl[] = { + IE_NA, /* ATM AAL Parameters */ + IE_NA, /* ATM User Cell Rate */ + IE_NA, /* Broadband Bearer Capability */ + IE_NA, /* Broadband High Layer Information */ + IE_NA, /* Broadband Low Layer Information */ + IE_NA, /* Call State */ + IE_NA, /* Called Party Number */ + IE_NA, /* Called Party Subaddress */ + IE_NA, /* Calling Party Number */ + IE_NA, /* Calling Party Subaddress */ + IE_NA, /* Cause */ + IE_NA, /* Connection Identifier */ + IE_NA, /* Quality of Service Parameters */ + IE_NA, /* Broadband Repeat Indicator */ + IE_NA, /* Restart Indicator */ + IE_NA, /* Broadband Locking Shift */ + IE_NA, /* Broadband Non-locking Shift */ + IE_NA, /* Broadband Sending Complete */ + IE_NA, /* Transit Net */ + IE_OPT, /* Endpoint Reference */ + IE_NA /* Endpoint State */ +}; + +static u_char uni_addp_ie_tbl[] = { + IE_OPT, /* ATM AAL Parameters */ + IE_NA, /* ATM User Cell Rate */ + IE_NA, /* Broadband Bearer Capability */ + IE_OPT, /* Broadband High Layer Information */ + IE_OPT, /* Broadband Low Layer Information */ + IE_NA, /* Call State */ + IE_MAND, /* Called Party Number */ + IE_OPT, /* Called Party Subaddress */ + IE_OPT, /* Calling Party Number */ + IE_OPT, /* Calling Party Subaddress */ + IE_NA, /* Cause */ + IE_NA, /* Connection Identifier */ + IE_NA, /* Quality of Service Parameters */ + IE_NA, /* Broadband Repeat Indicator */ + IE_NA, /* Restart Indicator */ + IE_NA, /* Broadband Locking Shift */ + IE_NA, /* Broadband Non-locking Shift */ + IE_OPT, /* Broadband Sending Complete */ + IE_NA, /* Transit Net */ + IE_MAND, /* Endpoint Reference */ + IE_NA /* Endpoint State */ +}; + +static u_char uni_adpa_ie_tbl[] = { + IE_NA, /* ATM AAL Parameters */ + IE_NA, /* ATM User Cell Rate */ + IE_NA, /* Broadband Bearer Capability */ + IE_NA, /* Broadband High Layer Information */ + IE_NA, /* Broadband Low Layer Information */ + IE_NA, /* Call State */ + IE_NA, /* Called Party Number */ + IE_NA, /* Called Party Subaddress */ + IE_NA, /* Calling Party Number */ + IE_NA, /* Calling Party Subaddress */ + IE_NA, /* Cause */ + IE_NA, /* Connection Identifier */ + IE_NA, /* Quality of Service Parameters */ + IE_NA, /* Broadband Repeat Indicator */ + IE_NA, /* Restart Indicator */ + IE_NA, /* Broadband Locking Shift */ + IE_NA, /* Broadband Non-locking Shift */ + IE_NA, /* Broadband Sending Complete */ + IE_NA, /* Transit Net */ + IE_MAND, /* Endpoint Reference */ + IE_NA /* Endpoint State */ +}; + +static u_char uni_adpr_ie_tbl[] = { + IE_NA, /* ATM AAL Parameters */ + IE_NA, /* ATM User Cell Rate */ + IE_NA, /* Broadband Bearer Capability */ + IE_NA, /* Broadband High Layer Information */ + IE_NA, /* Broadband Low Layer Information */ + IE_NA, /* Call State */ + IE_NA, /* Called Party Number */ + IE_NA, /* Called Party Subaddress */ + IE_NA, /* Calling Party Number */ + IE_NA, /* Calling Party Subaddress */ + IE_MAND, /* Cause */ + IE_NA, /* Connection Identifier */ + IE_NA, /* Quality of Service Parameters */ + IE_NA, /* Broadband Repeat Indicator */ + IE_NA, /* Restart Indicator */ + IE_NA, /* Broadband Locking Shift */ + IE_NA, /* Broadband Non-locking Shift */ + IE_NA, /* Broadband Sending Complete */ + IE_NA, /* Transit Net */ + IE_MAND, /* Endpoint Reference */ + IE_NA /* Endpoint State */ +}; + +static u_char uni_drpp_ie_tbl[] = { + IE_NA, /* ATM AAL Parameters */ + IE_NA, /* ATM User Cell Rate */ + IE_NA, /* Broadband Bearer Capability */ + IE_NA, /* Broadband High Layer Information */ + IE_NA, /* Broadband Low Layer Information */ + IE_NA, /* Call State */ + IE_NA, /* Called Party Number */ + IE_NA, /* Called Party Subaddress */ + IE_NA, /* Calling Party Number */ + IE_NA, /* Calling Party Subaddress */ + IE_MAND, /* Cause */ + IE_NA, /* Connection Identifier */ + IE_NA, /* Quality of Service Parameters */ + IE_NA, /* Broadband Repeat Indicator */ + IE_NA, /* Restart Indicator */ + IE_NA, /* Broadband Locking Shift */ + IE_NA, /* Broadband Non-locking Shift */ + IE_NA, /* Broadband Sending Complete */ + IE_NA, /* Transit Net */ + IE_MAND, /* Endpoint Reference */ + IE_NA /* Endpoint State */ +}; + +static u_char uni_drpa_ie_tbl[] = { + IE_NA, /* ATM AAL Parameters */ + IE_NA, /* ATM User Cell Rate */ + IE_NA, /* Broadband Bearer Capability */ + IE_NA, /* Broadband High Layer Information */ + IE_NA, /* Broadband Low Layer Information */ + IE_NA, /* Call State */ + IE_NA, /* Called Party Number */ + IE_NA, /* Called Party Subaddress */ + IE_NA, /* Calling Party Number */ + IE_NA, /* Calling Party Subaddress */ + IE_OPT, /* Cause */ + IE_NA, /* Connection Identifier */ + IE_NA, /* Quality of Service Parameters */ + IE_NA, /* Broadband Repeat Indicator */ + IE_NA, /* Restart Indicator */ + IE_NA, /* Broadband Locking Shift */ + IE_NA, /* Broadband Non-locking Shift */ + IE_NA, /* Broadband Sending Complete */ + IE_NA, /* Transit Net */ + IE_MAND, /* Endpoint Reference */ + IE_NA /* Endpoint State */ +}; + +/* + * Table of Q.2931 message types + */ +static struct { + u_char msg_type; + u_char *msg_ie_tbl; +} uni_msg_types[] = { + { UNI_MSG_CALP, uni_calp_ie_tbl }, + { UNI_MSG_CONN, uni_conn_ie_tbl }, + { UNI_MSG_CACK, uni_cack_ie_tbl }, + { UNI_MSG_SETU, uni_setu_ie_tbl }, + { UNI_MSG_RLSE, uni_rlse_ie_tbl }, + { UNI_MSG_RLSC, uni_rlsc_ie_tbl }, + { UNI_MSG_RSTR, uni_rstr_ie_tbl }, + { UNI_MSG_RSTA, uni_rsta_ie_tbl }, + { UNI_MSG_STAT, uni_stat_ie_tbl }, + { UNI_MSG_SENQ, uni_senq_ie_tbl }, + { UNI_MSG_ADDP, uni_addp_ie_tbl }, + { UNI_MSG_ADPA, uni_adpa_ie_tbl }, + { UNI_MSG_ADPR, uni_adpr_ie_tbl }, + { UNI_MSG_DRPP, uni_drpp_ie_tbl }, + { UNI_MSG_DRPA, uni_drpa_ie_tbl }, +}; + + +/* + * Table of information elements + */ +static struct ie_ent ie_table[] = { + { UNI_IE_AALP, 5, 16, UNI_MSG_IE_AALP, usf_dec_ie_aalp }, + { UNI_IE_CLRT, 0, 26, UNI_MSG_IE_CLRT, usf_dec_ie_clrt }, + { UNI_IE_BBCP, 2, 3, UNI_MSG_IE_BBCP, usf_dec_ie_bbcp }, + { UNI_IE_BHLI, 1, 9, UNI_MSG_IE_BHLI, usf_dec_ie_bhli }, + { UNI_IE_BLLI, 0, 13, UNI_MSG_IE_BLLI, usf_dec_ie_blli }, + { UNI_IE_CLST, 1, 1, UNI_MSG_IE_CLST, usf_dec_ie_clst }, + { UNI_IE_CDAD, 1, 21, UNI_MSG_IE_CDAD, usf_dec_ie_cdad }, + { UNI_IE_CDSA, 1, 21, UNI_MSG_IE_CDSA, usf_dec_ie_cdsa }, + { UNI_IE_CGAD, 1, 22, UNI_MSG_IE_CGAD, usf_dec_ie_cgad }, + { UNI_IE_CGSA, 1, 21, UNI_MSG_IE_CGSA, usf_dec_ie_cgsa }, + { UNI_IE_CAUS, 2, 30, UNI_MSG_IE_CAUS, usf_dec_ie_caus }, + { UNI_IE_CNID, 5, 5, UNI_MSG_IE_CNID, usf_dec_ie_cnid }, + { UNI_IE_QOSP, 2, 2, UNI_MSG_IE_QOSP, usf_dec_ie_qosp }, + { UNI_IE_BRPI, 1, 1, UNI_MSG_IE_BRPI, usf_dec_ie_brpi }, + { UNI_IE_RSTI, 1, 1, UNI_MSG_IE_RSTI, usf_dec_ie_rsti }, + { UNI_IE_BLSH, 1, 1, UNI_MSG_IE_ERR, usf_dec_ie_uimp }, + { UNI_IE_BNSH, 1, 1, UNI_MSG_IE_ERR, usf_dec_ie_uimp }, + { UNI_IE_BSDC, 1, 1, UNI_MSG_IE_BSDC, usf_dec_ie_bsdc }, + { UNI_IE_TRNT, 1, 5, UNI_MSG_IE_TRNT, usf_dec_ie_trnt }, + { UNI_IE_EPRF, 3, 3, UNI_MSG_IE_ERR, usf_dec_ie_uimp }, + { UNI_IE_EPST, 1, 1, UNI_MSG_IE_ERR, usf_dec_ie_uimp }, + { 0, 0, 0, 0, 0 } +}; + +/* + * Decoding table for AAL 1 + */ +struct ie_decode_tbl ie_aal1_tbl[] = { + { 133, 1, IE_OFF_SIZE(ie_aalp_1_subtype) }, + { 134, 1, IE_OFF_SIZE(ie_aalp_1_cbr_rate) }, + { 135, 2, IE_OFF_SIZE(ie_aalp_1_multiplier) }, + { 136, 1, IE_OFF_SIZE(ie_aalp_1_clock_recovery) }, + { 137, 1, IE_OFF_SIZE(ie_aalp_1_error_correction) }, + { 138, 1, IE_OFF_SIZE(ie_aalp_1_struct_data_tran) }, + { 139, 1, IE_OFF_SIZE(ie_aalp_1_partial_cells) }, + { 0, 0, 0, 0 } +}; + +/* + * Decoding table for AAL 3/4 + */ +struct ie_decode_tbl ie_aal4_tbl_30[] = { + { 140, 2, IE_OFF_SIZE(ie_aalp_4_fwd_max_sdu) }, + { 129, 2, IE_OFF_SIZE(ie_aalp_4_bkwd_max_sdu) }, + { 130, 2, IE_OFF_SIZE(ie_aalp_4_mid_range) }, + { 131, 1, IE_OFF_SIZE(ie_aalp_4_mode) }, + { 132, 1, IE_OFF_SIZE(ie_aalp_4_sscs_type) }, + { 0, 0, 0, 0 } +}; +struct ie_decode_tbl ie_aal4_tbl_31[] = { + { 140, 2, IE_OFF_SIZE(ie_aalp_4_fwd_max_sdu) }, + { 129, 2, IE_OFF_SIZE(ie_aalp_4_bkwd_max_sdu) }, + { 130, 4, IE_OFF_SIZE(ie_aalp_4_mid_range) }, + { 132, 1, IE_OFF_SIZE(ie_aalp_4_sscs_type) }, + { 0, 0, 0, 0 } +}; + +/* + * Decoding table for AAL 5 + */ +struct ie_decode_tbl ie_aal5_tbl_30[] = { + { 140, 2, IE_OFF_SIZE(ie_aalp_5_fwd_max_sdu) }, + { 129, 2, IE_OFF_SIZE(ie_aalp_5_bkwd_max_sdu) }, + { 131, 1, IE_OFF_SIZE(ie_aalp_5_mode) }, + { 132, 1, IE_OFF_SIZE(ie_aalp_5_sscs_type) }, + { 0, 0, 0, 0 } +}; +struct ie_decode_tbl ie_aal5_tbl_31[] = { + { 140, 2, IE_OFF_SIZE(ie_aalp_5_fwd_max_sdu) }, + { 129, 2, IE_OFF_SIZE(ie_aalp_5_bkwd_max_sdu) }, + { 132, 1, IE_OFF_SIZE(ie_aalp_5_sscs_type) }, + { 0, 0, 0, 0 } +}; + +/* + * Decoding table for ATM user cell rate + */ +struct ie_decode_tbl ie_clrt_tbl[] = { + {UNI_IE_CLRT_FWD_PEAK_ID, 3, IE_OFF_SIZE(ie_clrt_fwd_peak)}, + {UNI_IE_CLRT_BKWD_PEAK_ID, 3, IE_OFF_SIZE(ie_clrt_bkwd_peak)}, + {UNI_IE_CLRT_FWD_PEAK_01_ID, 3, IE_OFF_SIZE(ie_clrt_fwd_peak_01)}, + {UNI_IE_CLRT_BKWD_PEAK_01_ID, 3, IE_OFF_SIZE(ie_clrt_bkwd_peak_01)}, + {UNI_IE_CLRT_FWD_SUST_ID, 3, IE_OFF_SIZE(ie_clrt_fwd_sust)}, + {UNI_IE_CLRT_BKWD_SUST_ID, 3, IE_OFF_SIZE(ie_clrt_bkwd_sust)}, + {UNI_IE_CLRT_FWD_SUST_01_ID, 3, IE_OFF_SIZE(ie_clrt_fwd_sust_01)}, + {UNI_IE_CLRT_BKWD_SUST_01_ID, 3, IE_OFF_SIZE(ie_clrt_bkwd_sust_01)}, + {UNI_IE_CLRT_FWD_BURST_ID, 3, IE_OFF_SIZE(ie_clrt_fwd_burst)}, + {UNI_IE_CLRT_BKWD_BURST_ID, 3, IE_OFF_SIZE(ie_clrt_bkwd_burst)}, + {UNI_IE_CLRT_FWD_BURST_01_ID, 3, IE_OFF_SIZE(ie_clrt_fwd_burst_01)}, + {UNI_IE_CLRT_BKWD_BURST_01_ID, 3, IE_OFF_SIZE(ie_clrt_bkwd_burst_01)}, + {UNI_IE_CLRT_BEST_EFFORT_ID, 0, IE_OFF_SIZE(ie_clrt_best_effort)}, + {UNI_IE_CLRT_TM_OPTIONS_ID, 1, IE_OFF_SIZE(ie_clrt_tm_options)}, + {0, 0, 0, 0 } +}; + +/* + * IEs initialized to empty values + */ +struct ie_aalp ie_aalp_absent = { + T_ATM_ABSENT +}; + +struct ie_clrt ie_clrt_absent = { + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT +}; + +struct ie_bbcp ie_bbcp_absent = { + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT +}; + +struct ie_bhli ie_bhli_absent = { + T_ATM_ABSENT, + { 0, 0, 0, 0, 0, 0, 0, 0 } +}; + +struct ie_blli ie_blli_absent = { + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + { 0, 0, 0 }, + { 0, 0 } +}; + +struct ie_clst ie_clst_absent = { + T_ATM_ABSENT +}; + +struct ie_cdad ie_cdad_absent = { + T_ATM_ABSENT, + T_ATM_ABSENT, + { T_ATM_ABSENT, 0 } +}; + +struct ie_cdsa ie_cdsa_absent = { + { T_ATM_ABSENT, 0 } +}; + +struct ie_cgad ie_cgad_absent = { + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + { T_ATM_ABSENT, 0 } +}; + +struct ie_cgsa ie_cgsa_absent = { + { T_ATM_ABSENT, 0 } +}; + +struct ie_caus ie_caus_absent = { + T_ATM_ABSENT, + T_ATM_ABSENT, + 0 +}; + +struct ie_cnid ie_cnid_absent = { + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT, + T_ATM_ABSENT +}; + +struct ie_qosp ie_qosp_absent = { + T_ATM_ABSENT, + T_ATM_ABSENT +}; + +struct ie_brpi ie_brpi_absent = { + T_ATM_ABSENT +}; + +struct ie_rsti ie_rsti_absent = { + T_ATM_ABSENT +}; + +struct ie_blsh ie_blsh_absent = { + T_ATM_ABSENT +}; + +struct ie_bnsh ie_bnsh_absent = { + T_ATM_ABSENT +}; + +struct ie_bsdc ie_bsdc_absent = { + T_ATM_ABSENT +}; + +struct ie_trnt ie_trnt_absent = { + T_ATM_ABSENT, + T_ATM_ABSENT, + 0 +}; + +struct ie_eprf ie_eprf_absent = { + T_ATM_ABSENT, + T_ATM_ABSENT +}; + +struct ie_epst ie_epst_absent = { + T_ATM_ABSENT +}; + + +/* + * Decode a UNI signalling message + * + * Arguments: + * usf pointer to a unisig formatting structure + * msg pointer to a signalling message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +usf_dec_msg(usf, msg) + struct usfmt *usf; + struct unisig_msg *msg; +{ + int i, len, rc; + short s; + u_char c, *ie_tbl; + struct ie_generic *ie; + + ATM_DEBUG2("usf_dec_msg: usf=0x%x, msg=0x%x\n", (int) usf, + (int) msg); + + /* + * Check the total message length + */ + if (usf_count(usf) < UNI_MSG_MIN_LEN) { + return(EIO); + } + + /* + * Get and check the protocol discriminator + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + if (c != UNI_MSG_DISC_Q93B) + return(EIO); + + /* + * Get and check the call reference length + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + if (c != 3) + return(EIO); + + /* + * Get the call reference + */ + rc = usf_int3(usf, &msg->msg_call_ref); + if (rc) + return(rc); + + /* + * Get the message type + */ + rc = usf_byte(usf, &msg->msg_type); + if (rc) + return(rc); + + /* + * Get the message type extension + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + msg->msg_type_flag = (c >> UNI_MSG_TYPE_FLAG_SHIFT) & + UNI_MSG_TYPE_FLAG_MASK; + msg->msg_type_action = c & UNI_MSG_TYPE_ACT_MASK; + + /* + * Get the message length and make sure we actually have + * enough data for the whole message + */ + rc = usf_short(usf, &s); + if (rc) + return(rc); + msg->msg_length = s; + if (usf_count(usf) != msg->msg_length) { + return(EMSGSIZE); + } + + /* + * Process information elements + */ + len = msg->msg_length; + while (len) { + ALLOC_IE(ie); + rc = usf_dec_ie(usf, msg, ie); + if (rc) { + atm_free(ie); + return(rc); + } + len -= (ie->ie_length + UNI_IE_HDR_LEN); + } + + /* + * Make sure that mandatory IEs are included and + * unwanted ones aren't + */ + for (i=0; msg->msg_type!=uni_msg_types[i].msg_type && + uni_msg_types[i].msg_type!=0; i++) { + } + if (!uni_msg_types[i].msg_ie_tbl) + goto done; + + /* + * If the message type is in the table, check the IEs. + * If it isn't, the receive routine will catch the error. + */ + ie_tbl = uni_msg_types[i].msg_ie_tbl; + for (i=0; i<UNI_MSG_IE_CNT-1; i++) { + switch(ie_tbl[i]) { + case IE_MAND: + if (!msg->msg_ie_vec[i]) { + /* + * Mandatory IE missing + */ + ALLOC_IE(ie); + ie->ie_ident = unisig_ie_ident_vec[i]; + ie->ie_err_cause = UNI_IE_CAUS_MISSING; + MSG_IE_ADD(msg, ie, UNI_MSG_IE_ERR); + } + break; + case IE_NA: + if (msg->msg_ie_vec[i]) { + /* + * Disallowed IE present + */ + ie = msg->msg_ie_vec[i]; + msg->msg_ie_vec[i] = + (struct ie_generic *) 0; + MSG_IE_ADD(msg, ie, UNI_MSG_IE_ERR); + while (ie) { + ie->ie_err_cause = + UNI_IE_CAUS_IEEXIST; + ie = ie->ie_next; + } + } + break; + case IE_OPT: + break; + } + } + +done: + return(0); +} + + +/* + * Decode an information element + * + * This routine will be called repeatedly as long as there are + * information elements left to be decoded. It will decode the + * first part of the IE, look its type up in a table, and call + * the appropriate routine to decode the rest. After an IE is + * successfully decoded, it is linked into the UNI signalling + * message structure. If an error is discovered, the IE is linked + * into the IE error chain and an error cause is set in the header. + * + * Arguments: + * usf pointer to a UNISIG formatting structure + * msg pointer to a UNISIG message structure + * ie pointer to a generic IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie(usf, msg, ie) + struct usfmt *usf; + struct unisig_msg *msg; + struct ie_generic *ie; +{ + int i, ie_index, rc; + + /* + * Decode the IE header (identifier, instruction field, + * and length) + */ + rc = usf_dec_ie_hdr(usf, ie); + if (rc) + return(rc); + /* + * Ignore the IE if it is of zero length. + */ + if (!ie->ie_length) { + atm_free(ie); + return(0); + } + + /* + * Look up the information element in the table + */ + for (i=0; (ie->ie_ident != ie_table[i].ident) && + (ie_table[i].decode != NULL); i++) { + } + if (ie_table[i].decode == NULL) { + /* + * Unrecognized IE + */ + ie_index = UNI_MSG_IE_ERR; + } else { + ie_index = ie_table[i].p_idx; + } + + /* + * Check for unimplemented or unrecognized IEs + */ + if (ie_index == UNI_MSG_IE_ERR) { + ie->ie_err_cause = UNI_IE_CAUS_IEEXIST; + + /* + * Skip over the invalid IE + */ + rc = usf_dec_ie_uimp(usf, ie); + if (rc) + return(rc); + goto done; + } + + /* + * Check the length against the IE table + */ + if (ie->ie_length < ie_table[i].min_len || + ie->ie_length > ie_table[i].max_len) { + ie_index = UNI_MSG_IE_ERR; + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + + /* + * Skip over the invalid IE + */ + rc = usf_dec_ie_uimp(usf, ie); + if (rc) + return(rc); + goto done; + } + + /* + * Process the IE by calling the function indicated + * in the IE table + */ + rc = ie_table[i].decode(usf, ie); + if (rc) + return(rc); + + /* + * Link the IE into the signalling message + */ +done: + if (ie->ie_err_cause) { + ie_index = UNI_MSG_IE_ERR; + } + MSG_IE_ADD(msg, ie, ie_index); + + return(0); +} + + +/* + * Decode an information element header + * + * Arguments: + * usf pointer to a UNISIG formatting structure + * ie pointer to a generic IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_hdr(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + u_char c; + short s; + int rc; + + /* + * Get the IE identifier + */ + rc = usf_byte(usf, &ie->ie_ident); + if (rc) + return(rc); + + /* + * Get the extended type + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_coding = (c >> UNI_IE_CODE_SHIFT) & UNI_IE_CODE_MASK; + ie->ie_flag = (c >> UNI_IE_FLAG_SHIFT) & UNI_IE_FLAG_MASK; + ie->ie_action = c & UNI_IE_ACT_MASK; + + /* + * Get the length. + */ + rc = usf_short(usf, &s); + if (rc) + return(rc); + ie->ie_length = s; + + return(0); +} + + +/* + * Decode an AAL parameters information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to an AAL parms IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_aalp(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int i, rc = 0; + + /* + * Clear the IE + */ + KM_COPY(&ie_aalp_absent, &ie->ie_u.ie_aalp, + sizeof(ie_aalp_absent)); + + /* + * Get the AAL type + */ + rc = usf_byte(usf, &ie->ie_aalp_aal_type); + if (rc) + return(rc); + + /* + * Subtract the length of the AAL type from the total. + * It will be readjusted after usf_dec_ie_ident is finished. + */ + ie->ie_length--; + + /* + * Process based on AAL type + */ + switch (ie->ie_aalp_aal_type) { + case UNI_IE_AALP_AT_AAL1: + /* + * Clear the AAL 1 subparameters + */ + ie->ie_aalp_1_subtype = T_ATM_ABSENT; + ie->ie_aalp_1_cbr_rate = T_ATM_ABSENT; + ie->ie_aalp_1_multiplier = T_ATM_ABSENT; + ie->ie_aalp_1_clock_recovery = T_ATM_ABSENT; + ie->ie_aalp_1_error_correction = T_ATM_ABSENT; + ie->ie_aalp_1_struct_data_tran = T_ATM_ABSENT; + ie->ie_aalp_1_partial_cells = T_ATM_ABSENT; + + /* + * Parse the AAL fields based on their IDs + */ + rc = usf_dec_ie_ident(usf, ie, ie_aal1_tbl); + break; + case UNI_IE_AALP_AT_AAL3: + /* + * Clear the AAL 3/4 subparameters + */ + ie->ie_aalp_4_fwd_max_sdu = T_ATM_ABSENT; + ie->ie_aalp_4_bkwd_max_sdu = T_ATM_ABSENT; + ie->ie_aalp_4_mid_range = T_ATM_ABSENT; + ie->ie_aalp_4_mode = T_ATM_ABSENT; + ie->ie_aalp_4_sscs_type = T_ATM_ABSENT; + + /* + * Parse the AAL fields based on their IDs + */ + if (usf->usf_sig->us_proto == ATM_SIG_UNI30) + rc = usf_dec_ie_ident(usf, ie, ie_aal4_tbl_30); + else + rc = usf_dec_ie_ident(usf, ie, ie_aal4_tbl_31); + + /* + * If either forward or backward maximum SDU + * size is specified, the other must also be + * specified. + */ + if ((ie->ie_aalp_4_fwd_max_sdu != T_ATM_ABSENT && + ie->ie_aalp_4_bkwd_max_sdu == T_ATM_ABSENT) || + (ie->ie_aalp_4_fwd_max_sdu == T_ATM_ABSENT && + ie->ie_aalp_4_bkwd_max_sdu != T_ATM_ABSENT)) { + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + } + break; + case UNI_IE_AALP_AT_AAL5: + /* + * Clear the AAL 5 subparameters + */ + ie->ie_aalp_5_fwd_max_sdu = T_ATM_ABSENT; + ie->ie_aalp_5_bkwd_max_sdu = T_ATM_ABSENT; + ie->ie_aalp_5_mode = T_ATM_ABSENT; + ie->ie_aalp_5_sscs_type = T_ATM_ABSENT; + + /* + * Parse the AAL fields based on their IDs + */ + if (usf->usf_sig->us_proto == ATM_SIG_UNI30) + rc = usf_dec_ie_ident(usf, ie, ie_aal5_tbl_30); + else + rc = usf_dec_ie_ident(usf, ie, ie_aal5_tbl_31); + + /* + * If either forward or backward maximum SDU + * size is specified, the other must also be + * specified. + */ + if ((ie->ie_aalp_5_fwd_max_sdu != T_ATM_ABSENT && + ie->ie_aalp_5_bkwd_max_sdu == T_ATM_ABSENT) || + (ie->ie_aalp_5_fwd_max_sdu == T_ATM_ABSENT && + ie->ie_aalp_5_bkwd_max_sdu != T_ATM_ABSENT)) { + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + } + break; + case UNI_IE_AALP_AT_AALU: + /* + * Check user parameter length + */ + if (ie->ie_length > + sizeof(ie->ie_aalp_user_info) + + 1) { + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + } + + /* + * Get the user data + */ + i = 0; + while (i < ie->ie_length - 2) { + rc = usf_byte(usf, &ie->ie_aalp_user_info[i]); + if (rc) + break; + i++; + } + break; + default: + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + } + ie->ie_length++; + + return(rc); +} + + +/* + * Decode a user cell rate information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_clrt(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + + /* + * Clear the IE + */ + KM_COPY(&ie_clrt_absent, &ie->ie_u.ie_clrt, + sizeof(ie_clrt_absent)); + + /* + * Parse the IE using field identifiers + */ + rc = usf_dec_ie_ident(usf, ie, ie_clrt_tbl); + return(rc); +} + + +/* + * Decode a broadband bearer capability information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_bbcp(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + u_char c; + + /* + * Clear the IE + */ + KM_COPY(&ie_bbcp_absent, &ie->ie_u.ie_bbcp, + sizeof(ie_bbcp_absent)); + + /* + * Get the broadband bearer class + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_bbcp_bearer_class = c & UNI_IE_BBCP_BC_MASK; + + /* + * If the broadband bearer class was X, the next + * byte has the traffic type and timing requirements + */ + if (ie->ie_bbcp_bearer_class == UNI_IE_BBCP_BC_BCOB_X && + !(c & UNI_IE_EXT_BIT)) { + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_bbcp_traffic_type = (c >> UNI_IE_BBCP_TT_SHIFT) & + UNI_IE_BBCP_TT_MASK; + ie->ie_bbcp_timing_req = c & UNI_IE_BBCP_TR_MASK; + } + + /* + * Get the clipping and user plane connection configuration + */ + if (c & UNI_IE_EXT_BIT) { + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_bbcp_clipping = (c >> UNI_IE_BBCP_SC_SHIFT) & + UNI_IE_BBCP_SC_MASK; + ie->ie_bbcp_conn_config = c & UNI_IE_BBCP_CC_MASK; + } + + return(0); +} + + +/* + * Decode a broadband high layer information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_bhli(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int i, rc; + u_char c; + + /* + * Clear the IE + */ + KM_COPY(&ie_bhli_absent, &ie->ie_u.ie_bhli, + sizeof(ie_bhli_absent)); + + /* + * Get the high layer information type + */ + rc = usf_ext(usf, &i); + ie->ie_bhli_type = i & UNI_IE_EXT_MASK; + if (rc) + return(rc); + + /* + * What comes next depends on the type + */ + switch (ie->ie_bhli_type) { + case UNI_IE_BHLI_TYPE_ISO: + case UNI_IE_BHLI_TYPE_USER: + /* + * ISO or user-specified parameters -- take the + * length of information from the IE length + */ + for (i=0; i<ie->ie_length-1; i++) { + rc = usf_byte(usf, &ie->ie_bhli_info[i]); + if (rc) + return(rc); + } + break; + case UNI_IE_BHLI_TYPE_HLP: + /* + * Make sure the IE is long enough for the high + * layer profile information, then get it + */ + if (usf->usf_sig->us_proto != ATM_SIG_UNI30) + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + if (ie->ie_length < UNI_IE_BHLI_HLP_LEN+1) + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + for (i=0; i<ie->ie_length && + i<UNI_IE_BHLI_HLP_LEN; i++) { + rc = usf_byte(usf, &ie->ie_bhli_info[i]); + if (rc) + return(rc); + } + break; + case UNI_IE_BHLI_TYPE_VSA: + /* + * Make sure the IE is long enough for the vendor- + * specific application information, then get it + */ + if (ie->ie_length < UNI_IE_BHLI_VSA_LEN+1) + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + for (i=0; i<ie->ie_length && + i<UNI_IE_BHLI_VSA_LEN; i++) { + rc = usf_byte(usf, &ie->ie_bhli_info[i]); + if (rc) + return(rc); + } + break; + default: + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + for (i=0; i<ie->ie_length; i++) { + rc = usf_byte(usf, &c); + if (rc) + return(rc); + } + } + + return(0); +} + + +/* + * Decode a broadband low layer information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_blli(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + u_char c, id; + int bc, i, rc; + u_int ipi; + + /* + * Clear the IE + */ + KM_COPY(&ie_blli_absent, &ie->ie_u.ie_blli, + sizeof(ie_blli_absent)); + + /* + * Get paramteters for the protocol layers as long as + * there is still information left in the IE + */ + bc = ie->ie_length; + while (bc) { + /* + * Get the type and process based on what it is + */ + rc = usf_byte(usf, &id); + if (rc) + return(rc); + switch (((id & UNI_IE_EXT_MASK) >> + UNI_IE_BLLI_LID_SHIFT) & + UNI_IE_BLLI_LID_MASK) { + case UNI_IE_BLLI_L1_ID: + /* + * Layer 1 info + */ + ie->ie_blli_l1_id = id & UNI_IE_BLLI_LP_MASK; + bc--; + break; + case UNI_IE_BLLI_L2_ID: + /* + * Layer 2 info--contents vary based on type + */ + ie->ie_blli_l2_id = id & UNI_IE_BLLI_LP_MASK; + bc--; + if (id & UNI_IE_EXT_BIT) + break; + switch (ie->ie_blli_l2_id) { + case UNI_IE_BLLI_L2P_X25L: + case UNI_IE_BLLI_L2P_X25M: + case UNI_IE_BLLI_L2P_HDLC1: + case UNI_IE_BLLI_L2P_HDLC2: + case UNI_IE_BLLI_L2P_HDLC3: + case UNI_IE_BLLI_L2P_Q922: + case UNI_IE_BLLI_L2P_ISO7776: + rc = usf_byte(usf, &c); + if (rc) + return(rc); + bc--; + ie->ie_blli_l2_mode = (c >> + UNI_IE_BLLI_L2MODE_SHIFT) & + UNI_IE_BLLI_L2MODE_MASK; + if (!(c & UNI_IE_EXT_BIT)) + break; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + bc--; + ie->ie_blli_l2_window = + c & UNI_IE_EXT_MASK; + break; + case UNI_IE_BLLI_L2P_USER: + rc = usf_byte(usf, &c); + if (rc) + return(rc); + bc--; + ie->ie_blli_l2_user_proto = + c & UNI_IE_EXT_MASK; + break; + } + break; + case UNI_IE_BLLI_L3_ID: + /* + * Layer 3 info--contents vary based on type + */ + ie->ie_blli_l3_id = id & UNI_IE_BLLI_LP_MASK; + bc--; + switch (ie->ie_blli_l3_id) { + case UNI_IE_BLLI_L3P_X25: + case UNI_IE_BLLI_L3P_ISO8208: + case UNI_IE_BLLI_L3P_ISO8878: + rc = usf_byte(usf, &c); + if (rc) + return(rc); + bc--; + ie->ie_blli_l3_mode = (c >> + UNI_IE_BLLI_L3MODE_SHIFT) & + UNI_IE_BLLI_L3MODE_MASK; + if (!(c & UNI_IE_EXT_BIT)) + break; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + bc--; + ie->ie_blli_l3_packet_size = + c & UNI_IE_BLLI_L3PS_MASK; + if (!(c & UNI_IE_EXT_BIT)) + break; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + bc--; + ie->ie_blli_l3_window = + c & UNI_IE_EXT_MASK; + break; + case UNI_IE_BLLI_L3P_USER: + rc = usf_byte(usf, &c); + if (rc) + return(rc); + bc--; + ie->ie_blli_l3_mode = + c & UNI_IE_EXT_MASK; + break; + case UNI_IE_BLLI_L3P_ISO9577: + rc = usf_ext(usf, &ipi); + if (rc) + return(rc); + bc -= 2; + ie->ie_blli_l3_ipi = ipi >> + UNI_IE_BLLI_L3IPI_SHIFT; + if (ie->ie_blli_l3_ipi != + UNI_IE_BLLI_L3IPI_SNAP) + break; + + rc = usf_byte(usf, &c); + ie->ie_blli_l3_snap_id = c & UNI_IE_EXT_MASK; + if (rc) + return(rc); + bc --; + + rc = usf_byte(usf, + &ie->ie_blli_l3_oui[0]); + if (rc) + return(rc); + rc = usf_byte(usf, + &ie->ie_blli_l3_oui[1]); + if (rc) + return(rc); + rc = usf_byte(usf, + &ie->ie_blli_l3_oui[2]); + if (rc) + return(rc); + rc = usf_byte(usf, + &ie->ie_blli_l3_pid[0]); + if (rc) + return(rc); + rc = usf_byte(usf, + &ie->ie_blli_l3_pid[1]); + if (rc) + return(rc); + bc -= 5; + break; + } + break; + default: + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + for (i=0; i<ie->ie_length; i++) { + rc = usf_byte(usf, &c); + if (rc) + return(rc); + } + } + } + + return(0); +} + + +/* + * Decode a call state information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_clst(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + u_char c; + + /* + * Clear the IE + */ + KM_COPY(&ie_clst_absent, &ie->ie_u.ie_clst, + sizeof(ie_clst_absent)); + + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_clst_state = c & UNI_IE_CLST_STATE_MASK; + + return(0); +} + + +/* + * Decode a called party number information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_cdad(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int len, rc; + u_char c; + + /* + * Clear the IE + */ + KM_COPY(&ie_cdad_absent, &ie->ie_u.ie_cdad, + sizeof(ie_cdad_absent)); + + /* + * Get and check the numbering plan + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_cdad_plan = c & UNI_IE_CDAD_PLAN_MASK; + len = ie->ie_length - 1; + switch (ie->ie_cdad_plan) { + case UNI_IE_CDAD_PLAN_E164: + ie->ie_cdad_addr.address_format = T_ATM_E164_ADDR; + break; + case UNI_IE_CDAD_PLAN_NSAP: + ie->ie_cdad_addr.address_format = T_ATM_ENDSYS_ADDR; + break; + default: + /* + * Invalid numbering plan + */ + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + while (len) { + rc = usf_byte(usf, &c); + if (rc) + return(rc); + len--; + } + + return(0); + } + + /* + * Get the ATM address + */ + rc = usf_dec_atm_addr(usf, &ie->ie_cdad_addr, len); + if (rc == EINVAL) { + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + rc = 0; + } + + return(rc); +} + + +/* + * Decode a called party subaddress information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_cdsa(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int len, rc; + u_char c; + + /* + * Clear the IE + */ + KM_COPY(&ie_cdsa_absent, &ie->ie_u.ie_cdsa, + sizeof(ie_cdsa_absent)); + + /* + * Get and check the subaddress type + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + len = ie->ie_length - 1; + if (((c >> UNI_IE_CDSA_TYPE_SHIFT) & UNI_IE_CDSA_TYPE_MASK) != + UNI_IE_CDSA_TYPE_AESA) { + /* + * Invalid subaddress type + */ + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + while (len) { + rc = usf_byte(usf, &c); + if (rc) + return(rc); + len--; + } + + return(0); + } + + /* + * Get the ATM address + */ + ie->ie_cdsa_addr.address_format = T_ATM_ENDSYS_ADDR; + rc = usf_dec_atm_addr(usf, &ie->ie_cdsa_addr, len); + if (rc == EINVAL) { + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + rc = 0; + } + + return(rc); +} + + +/* + * Decode a calling party number information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_cgad(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int len, rc; + u_char c; + + /* + * Clear the IE + */ + KM_COPY(&ie_cgad_absent, &ie->ie_u.ie_cgad, + sizeof(ie_cgad_absent)); + + /* + * Get and check the numbering plan + */ + len = ie->ie_length; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_cgad_type = (c >> UNI_IE_CGAD_TYPE_SHIFT) & + UNI_IE_CGAD_TYPE_MASK; + ie->ie_cgad_plan = c & UNI_IE_CGAD_PLAN_MASK; + len--; + switch (ie->ie_cgad_plan) { + case UNI_IE_CGAD_PLAN_E164: + ie->ie_cgad_addr.address_format = T_ATM_E164_ADDR; + break; + case UNI_IE_CGAD_PLAN_NSAP: + ie->ie_cgad_addr.address_format = T_ATM_ENDSYS_ADDR; + break; + default: + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + while (len) { + rc = usf_byte(usf, &c); + if (rc) + return(rc); + len--; + } + + return(0); + } + + /* + * Get the presentation and screening indicators, if present + */ + if (!(c & UNI_IE_EXT_BIT)) { + rc = usf_byte(usf, &c); + if (rc) + return(rc); + len--; + ie->ie_cgad_pres_ind = (c >> UNI_IE_CGAD_PRES_SHIFT) & + UNI_IE_CGAD_PRES_MASK; + ie->ie_cgad_screen_ind = c & UNI_IE_CGAD_SCR_MASK; + } else { + ie->ie_cgad_pres_ind = 0; + ie->ie_cgad_screen_ind =0; + } + + /* + * Get the ATM address + */ + rc = usf_dec_atm_addr(usf, &ie->ie_cgad_addr, len); + if (rc == EINVAL) { + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + rc = 0; + } + + return(rc); +} + + +/* + * Decode a calling party subaddress information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_cgsa(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int len, rc; + u_char c; + + /* + * Clear the IE + */ + KM_COPY(&ie_cgsa_absent, &ie->ie_u.ie_cgsa, + sizeof(ie_cgsa_absent)); + + /* + * Get and check the subaddress type + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + len = ie->ie_length - 1; + if (((c >> UNI_IE_CGSA_TYPE_SHIFT) & UNI_IE_CGSA_TYPE_MASK) != + UNI_IE_CGSA_TYPE_AESA) { + /* + * Invalid subaddress type + */ + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + while (len) { + rc = usf_byte(usf, &c); + if (rc) + return(rc); + len--; + } + + return(0); + } + + /* + * Get the ATM address + */ + ie->ie_cgsa_addr.address_format = T_ATM_ENDSYS_ADDR; + rc = usf_dec_atm_addr(usf, &ie->ie_cgsa_addr, len); + if (rc == EINVAL) { + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + rc = 0; + } + + return(rc); +} + + +/* + * Decode a cause information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_caus(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int i, len, rc; + u_char c; + + /* + * Clear the IE + */ + KM_COPY(&ie_caus_absent, &ie->ie_u.ie_caus, + sizeof(ie_caus_absent)); + + /* + * Get the cause location + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_caus_loc = c & UNI_IE_CAUS_LOC_MASK; + + /* + * Get the cause value + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_caus_cause = c & UNI_IE_EXT_MASK; + + /* + * Get any included diagnostics + */ + len = ie->ie_length - 2; + for (i = 0, ie->ie_caus_diag_len = 0; + len && i < sizeof(ie->ie_caus_diagnostic); + len--, i++, ie->ie_caus_diag_len++) { + rc = usf_byte(usf, &ie->ie_caus_diagnostic[i]); + if (rc) + return(rc); + } + + return(0); +} + + +/* + * Decode a conection identifier information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_cnid(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int i, rc; + + /* + * Clear the IE + */ + KM_COPY(&ie_cnid_absent, &ie->ie_u.ie_cnid, + sizeof(ie_cnid_absent)); + + rc = usf_ext(usf, &i); + if (rc) + return(rc); + ie->ie_cnid_vp_sig = (i >> UNI_IE_CNID_VPSIG_SHIFT) & + UNI_IE_CNID_VPSIG_MASK; + ie->ie_cnid_pref_excl = i & UNI_IE_CNID_PREX_MASK; + + rc = usf_short(usf, &ie->ie_cnid_vpci); + if (rc) + return(rc); + rc = usf_short(usf, &ie->ie_cnid_vci); + return(rc); +} + + +/* + * Decode a quality of service parameters information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_qosp(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + + /* + * Clear the IE + */ + KM_COPY(&ie_qosp_absent, &ie->ie_u.ie_qosp, + sizeof(ie_qosp_absent)); + + /* + * Get forward QoS class + */ + rc = usf_byte(usf, &ie->ie_qosp_fwd_class); + if (rc) + return(rc); + + /* + * Get backward QoS class + */ + rc = usf_byte(usf, &ie->ie_qosp_bkwd_class); + + return(rc); +} + + +/* + * Decode a broadband repeat indicator information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_brpi(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + u_char c; + + /* + * Clear the IE + */ + KM_COPY(&ie_brpi_absent, &ie->ie_u.ie_brpi, + sizeof(ie_brpi_absent)); + + /* + * Get the repeat indicator + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + ie->ie_brpi_ind = c & UNI_IE_BRPI_IND_MASK; + + return(0); +} + + +/* + * Decode a restart indicator information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_rsti(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + u_char c; + + /* + * Clear the IE + */ + KM_COPY(&ie_rsti_absent, &ie->ie_u.ie_rsti, + sizeof(ie_rsti_absent)); + + /* + * Get the restart class + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + ie->ie_rsti_class = c & UNI_IE_RSTI_CLASS_MASK; + + return(0); +} + + +/* + * Decode a broadband sending complete information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a broadband sending complete IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_bsdc(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + u_char c; + + /* + * Clear the IE + */ + KM_COPY(&ie_bsdc_absent, &ie->ie_u.ie_bsdc, + sizeof(ie_bsdc_absent)); + + /* + * Get the sending complete indicator + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Validate the indicator + */ + c &= UNI_IE_EXT_MASK; + if (c != UNI_IE_BSDC_IND) + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + ie->ie_bsdc_ind = c; + + return(0); +} + + +/* + * Decode a transit network selection information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a transit network selection IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_trnt(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int i, len, rc; + u_char c; + + /* + * Clear the IE + */ + KM_COPY(&ie_trnt_absent, &ie->ie_u.ie_trnt, + sizeof(ie_trnt_absent)); + + /* + * Get the network ID type and plan + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_trnt_id_type = (c >> UNI_IE_TRNT_IDT_SHIFT) & + UNI_IE_TRNT_IDT_MASK; + ie->ie_trnt_id_plan = c & UNI_IE_TRNT_IDP_MASK; + + /* + * Get the length of the network ID + */ + len = ie->ie_length - 1; + ie->ie_trnt_id_len = MIN(len, sizeof(ie->ie_trnt_id)); + + /* + * Get the network ID + */ + for (i=0; i<len; i++) { + if (i<sizeof(ie->ie_trnt_id)) + rc = usf_byte(usf, &ie->ie_trnt_id[i]); + else + rc = usf_byte(usf, &c); + if (rc) + return(rc); + } + + return(0); +} + + +/* + * Decode an unimplemented information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_uimp(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int i, rc; + u_char c; + + /* + * Skip over the IE contents + */ + for (i=0; i<ie->ie_length; i++) { + rc = usf_byte(usf, &c); + if (rc) + return(rc); + } + + return(0); +} + + +/* + * Decode an information element using field identifiers + * + * The AAL parameters and ATM user cell rate IEs are formatted + * with a one-byte identifier preceeding each field. The routine + * parses these IEs by using a table which relates the field + * identifiers with the fields in the appropriate IE structure. + * Field order in the received message is immaterial. + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * tbl pointer to an IE decoding table + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_ie_ident(usf, ie, tbl) + struct usfmt *usf; + struct ie_generic *ie; + struct ie_decode_tbl *tbl; +{ + int i, len, rc; + u_char c; + u_int8_t cv; + u_int16_t sv; + u_int32_t iv; + void *dest; + + /* + * Scan through the IE + */ + len = ie->ie_length; + while (len) { + /* + * Get the field identifier + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + len--; + + /* + * Look up the field in the table + */ + for (i=0; (tbl[i].ident != c) && tbl[i].len; i++) { + } + if (tbl[i].ident == 0) { + /* + * Bad subfield identifier -- flag an + * error and skip over the rest of the IE + */ + ie->ie_err_cause = UNI_IE_CAUS_IECONTENT; + while (len) { + rc = usf_byte(usf, &c); + if (rc) + return(rc); + } + return(0); + } + + /* + * Save final destination address + */ + dest = (void *)((int)ie + tbl[i].f_offs); + + /* + * Get the field value + */ + switch (tbl[i].len) { + case 0: + cv = 1; + goto savec; + + case 1: + rc = usf_byte(usf, &cv); + if (rc) + break; +savec: + /* + * Save field value + */ + switch (tbl[i].f_size) { + case 1: + *(u_int8_t *)dest = cv; + break; + case 2: + *(u_int16_t *)dest = cv; + break; + case 4: + *(u_int32_t *)dest = cv; + break; + default: + goto badtbl; + } + break; + + case 2: + rc = usf_short(usf, &sv); + if (rc) + break; + + /* + * Save field value + */ + switch (tbl[i].f_size) { + case 2: + *(u_int16_t *)dest = sv; + break; + case 4: + *(u_int32_t *)dest = sv; + break; + default: + goto badtbl; + } + break; + + case 3: + rc = usf_int3(usf, &iv); + goto savei; + + case 4: + rc = usf_int(usf, &iv); +savei: + /* + * Save field value + */ + if (rc) + break; + switch (tbl[i].f_size) { + case 4: + *(u_int32_t *)dest = iv; + break; + default: + goto badtbl; + } + break; + + default: +badtbl: + log(LOG_ERR, + "uni decode: id=%d,len=%d,off=%d,size=%d\n", + tbl[i].ident, tbl[i].len, + tbl[i].f_offs, tbl[i].f_size); + rc = EFAULT; + break; + } + + if (rc) + return(rc); + + len -= tbl[i].len; + + } + + return(0); +} + + +/* + * Decode an ATM address + * + * Arguments: + * usf pointer to a unisig formatting structure + * addr pointer to an ATM address structure + * len length of data remainig in the IE + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_dec_atm_addr(usf, addr, len) + struct usfmt *usf; + Atm_addr *addr; + int len; +{ + int rc; + u_char c, *cp; + + /* + * Check the address type + */ + addr->address_length = len; + switch (addr->address_format) { + case T_ATM_E164_ADDR: + if (len > sizeof(Atm_addr_e164)) { + goto flush; + } + cp = (u_char *) addr->address; + break; + case T_ATM_ENDSYS_ADDR: + if (len != sizeof(Atm_addr_nsap)) { + goto flush; + } + cp = (u_char *) addr->address; + break; + default: + /* Silence the compiler */ + cp = NULL; + } + + /* + * Get the ATM address + */ + while (len) { + rc = usf_byte(usf, cp); + if (rc) + return(rc); + len--; + cp++; + } + + return(0); + +flush: + while (len) { + rc = usf_byte(usf, &c); + if (rc) + return(rc); + len--; + } + + return(EINVAL); +} diff --git a/sys/netatm/uni/unisig_decode.h b/sys/netatm/uni/unisig_decode.h new file mode 100644 index 0000000..dbd184a --- /dev/null +++ b/sys/netatm/uni/unisig_decode.h @@ -0,0 +1,87 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: unisig_decode.h,v 1.5 1998/08/26 23:29:21 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Message formats + * + */ + +#ifndef _UNI_SIG_DECODE_H +#define _UNI_SIG_DECODE_H + + +/* + * Values specifying which IEs are required in messages + */ +#define IE_NA 0 +#define IE_MAND 1 +#define IE_OPT 2 + +/* + * Structure for information element decoding information + */ +struct ie_ent { + u_char ident; /* IE identifier */ + int min_len; /* Min. length */ + int max_len; /* Max. length */ + int p_idx; /* IE pointer index in msg */ + int (*decode) /* Decoding function */ + __P((struct usfmt *, struct ie_generic *)); +}; + +/* + * Macro to give the offset of a field in a generic IE structure + */ +#define IE_OFFSET(f) \ + ((int)&((struct ie_generic *) 0)->f) + +/* + * Macro to give the size of a field in a generic IE structure + */ +#define IE_FSIZE(f) \ + (sizeof(((struct ie_generic *) 0)->f)) + +#define IE_OFF_SIZE(f) IE_OFFSET(f),IE_FSIZE(f) + + +/* + * Structure to define a field-driven decoding table (for AAL + * parameters and ATM user cell rate IEs) + */ +struct ie_decode_tbl { + u_char ident; + int len; + int f_offs; + int f_size; +}; + +#endif /* _UNI_SIG_DECODE_H */ diff --git a/sys/netatm/uni/unisig_encode.c b/sys/netatm/uni/unisig_encode.c new file mode 100644 index 0000000..0920acc --- /dev/null +++ b/sys/netatm/uni/unisig_encode.c @@ -0,0 +1,1681 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: unisig_encode.c,v 1.11 1998/08/26 23:29:21 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Message formatting module + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_encode.c,v 1.11 1998/08/26 23:29:21 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/unisig.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/unisig_msg.h> +#include <netatm/uni/unisig_mbuf.h> +#include <netatm/uni/unisig_decode.h> + + +/* + * Local functions + */ +static int usf_enc_ie __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_aalp __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_clrt __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_bbcp __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_bhli __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_blli __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_clst __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_cdad __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_cdsa __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_cgad __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_cgsa __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_caus __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_cnid __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_qosp __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_brpi __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_rsti __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_bsdc __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_trnt __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_uimp __P((struct usfmt *, struct ie_generic *)); +static int usf_enc_ie_ident __P((struct usfmt *, struct ie_generic *, + struct ie_decode_tbl *)); +static int usf_enc_atm_addr __P((struct usfmt *, Atm_addr *)); + + +/* + * Local variables + */ +static struct { + u_char ident; /* IE identifier */ + int (*encode) __P((struct usfmt *, struct ie_generic *)); + /* Encoding function */ +} ie_table[] = { + { UNI_IE_AALP, usf_enc_ie_aalp }, + { UNI_IE_CLRT, usf_enc_ie_clrt }, + { UNI_IE_BBCP, usf_enc_ie_bbcp }, + { UNI_IE_BHLI, usf_enc_ie_bhli }, + { UNI_IE_BLLI, usf_enc_ie_blli }, + { UNI_IE_CLST, usf_enc_ie_clst }, + { UNI_IE_CDAD, usf_enc_ie_cdad }, + { UNI_IE_CDSA, usf_enc_ie_cdsa }, + { UNI_IE_CGAD, usf_enc_ie_cgad }, + { UNI_IE_CGSA, usf_enc_ie_cgsa }, + { UNI_IE_CAUS, usf_enc_ie_caus }, + { UNI_IE_CNID, usf_enc_ie_cnid }, + { UNI_IE_QOSP, usf_enc_ie_qosp }, + { UNI_IE_BRPI, usf_enc_ie_brpi }, + { UNI_IE_RSTI, usf_enc_ie_rsti }, + { UNI_IE_BLSH, usf_enc_ie_uimp }, + { UNI_IE_BNSH, usf_enc_ie_uimp }, + { UNI_IE_BSDC, usf_enc_ie_bsdc }, + { UNI_IE_TRNT, usf_enc_ie_trnt }, + { UNI_IE_EPRF, usf_enc_ie_uimp }, + { UNI_IE_EPST, usf_enc_ie_uimp }, + { 0, 0 } +}; + +extern struct ie_decode_tbl ie_aal1_tbl[]; +extern struct ie_decode_tbl ie_aal4_tbl_30[]; +extern struct ie_decode_tbl ie_aal4_tbl_31[]; +extern struct ie_decode_tbl ie_aal5_tbl_30[]; +extern struct ie_decode_tbl ie_aal5_tbl_31[]; +extern struct ie_decode_tbl ie_clrt_tbl[]; + + +/* + * Encode a UNI signalling message + * + * Arguments: + * usf pointer to a unisig formatting structure + * msg pointer to a signalling message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +usf_enc_msg(usf, msg) + struct usfmt *usf; + struct unisig_msg *msg; +{ + int i, len, rc; + u_char c; + u_char *lp0, *lp1; + struct ie_generic *ie; + + union { + short s; + u_char sb[sizeof(short)]; + } su; + + ATM_DEBUG2("usf_enc_msg: usf=0x%x, msg=0x%x\n", + (int)usf, (int)msg); + + /* + * Encode the protocol discriminator + */ + c = UNI_MSG_DISC_Q93B; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Encode the call reference length + */ + c = 3; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Encode the call reference + */ + rc = usf_int3(usf, &msg->msg_call_ref); + if (rc) + return(rc); + + /* + * Encode the message type + */ + rc = usf_byte(usf, &msg->msg_type); + if (rc) + return(rc); + + /* + * Encode the message type extension + */ + c = ((msg->msg_type_flag & UNI_MSG_TYPE_FLAG_MASK) << + UNI_MSG_TYPE_FLAG_SHIFT) + + (msg->msg_type_action & UNI_MSG_TYPE_ACT_MASK) + + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Save the location of the message length and encode a length + * of zero for now. We'll fix the length up at the end. + */ + su.s = 0; + rc = usf_byte_mark(usf, &su.sb[sizeof(short)-2], &lp0); + if (rc) + return(rc); + rc = usf_byte_mark(usf, &su.sb[sizeof(short)-1], &lp1); + if (rc) + return(rc); + + /* + * Process information elements + */ + len = 0; + for (i=0; i<UNI_MSG_IE_CNT; i++) { + ie = msg->msg_ie_vec[i]; + while (ie) { + rc = usf_enc_ie(usf, ie); + if (rc) + return(rc); + len += (ie->ie_length + UNI_IE_HDR_LEN); + ie = ie->ie_next; + } + } + + /* + * Fix the message length in the encoded message + */ + su.s = htons((u_short)len); + *lp0 = su.sb[sizeof(short)-2]; + *lp1 = su.sb[sizeof(short)-1]; + + return(0); +} + + +/* + * Encode an information element + * + * Arguments: + * usf pointer to a UNISIG formatting structure + * msg pointer to a UNISIG message structure + * ie pointer to a generic IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int i, rc; + u_char c; + u_char *lp0, *lp1; + + union { + short s; + u_char sb[sizeof(short)]; + } su; + + ATM_DEBUG2("usf_enc_ie: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + /* + * Encode the IE identifier + */ + rc = usf_byte(usf, &ie->ie_ident); + if (rc) + return(rc); + + /* + * Encode the extended type + */ + c = ((ie->ie_coding & UNI_IE_CODE_MASK) << UNI_IE_CODE_SHIFT) + + ((ie->ie_flag & UNI_IE_FLAG_MASK) << + UNI_IE_FLAG_SHIFT) + + (ie->ie_action & UNI_IE_ACT_MASK) + + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Mark the current location in the output stream. Encode a + * length of zero for now; we'll come back and fix it up at + * the end. + */ + su.s = 0; + rc = usf_byte_mark(usf, &su.sb[sizeof(short)-2], &lp0); + if (rc) + return(rc); + rc = usf_byte_mark(usf, &su.sb[sizeof(short)-1], &lp1); + if (rc) + return(rc); + + /* + * Look up the information element in the table + */ + for (i=0; (ie->ie_ident != ie_table[i].ident) && + (ie_table[i].encode != NULL); i++) { + } + if (ie_table[i].encode == NULL) { + /* + * Unrecognized IE + */ + return(EINVAL); + } + + /* + * Process the IE by calling the function indicated + * in the IE table + */ + rc = ie_table[i].encode(usf, ie); + if (rc) + return(rc); + + /* + * Set the length in the output stream + */ + su.s = htons((u_short)ie->ie_length); + *lp0 = su.sb[sizeof(short)-2]; + *lp1 = su.sb[sizeof(short)-1]; + + return(0); +} + + +/* + * Encode an AAL parameters information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to an AAL parms IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_aalp(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int i, rc = 0; + + ATM_DEBUG2("usf_enc_ie_aalp: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + ie->ie_length = 0; + + /* + * Encode the AAL type + */ + if (ie->ie_aalp_aal_type == T_ATM_ABSENT) + return(0); + rc = usf_byte(usf, &ie->ie_aalp_aal_type); + if (rc) + return(rc); + + /* + * Process based on AAL type + */ + switch (ie->ie_aalp_aal_type) { + case UNI_IE_AALP_AT_AAL1: + rc = usf_enc_ie_ident(usf, ie, ie_aal1_tbl); + break; + case UNI_IE_AALP_AT_AAL3: + if (usf->usf_sig->us_proto == ATM_SIG_UNI30) + rc = usf_enc_ie_ident(usf, ie, ie_aal4_tbl_30); + else + rc = usf_enc_ie_ident(usf, ie, ie_aal4_tbl_31); + break; + case UNI_IE_AALP_AT_AAL5: + if (usf->usf_sig->us_proto == ATM_SIG_UNI30) + rc = usf_enc_ie_ident(usf, ie, ie_aal5_tbl_30); + else + rc = usf_enc_ie_ident(usf, ie, ie_aal5_tbl_31); + break; + case UNI_IE_AALP_AT_AALU: + /* + * Encode the user data + */ + i = 0; + while (i < sizeof(ie->ie_aalp_user_info)) { + rc = usf_byte(usf, &ie->ie_aalp_user_info[i]); + if (rc) + break; + i++; + ie->ie_length++; + } + break; + default: + return(EINVAL); + } + + ie->ie_length++; + return(rc); +} + + +/* + * Encode a user cell rate information element + * + * This routine just encodes the parameters required for best + * effort service. + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_clrt(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + + ATM_DEBUG2("usf_enc_ie_clrt: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + +#ifdef NOTDEF + /* + * Encode Peak Cell Rate Forward CLP = 0 + 1 + */ + c = UNI_IE_CLRT_FWD_PEAK_01_ID; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + rc = usf_int3(usf, &ie->ie_clrt_fwd_peak_01); + if (rc) + return(rc); + + /* + * Encode Peak Cell Rate Backward CLP = 0 + 1 + */ + c = UNI_IE_CLRT_BKWD_PEAK_01_ID; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + rc = usf_int3(usf, &ie->ie_clrt_bkwd_peak_01); + if (rc) + return(rc); + + /* + * Encode Best Effort Flag + */ + c = UNI_IE_CLRT_BEST_EFFORT_ID; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Set IE length + */ + ie->ie_length = 9; +#endif + + /* + * Encode the user cell rate IE using the table + */ + ie->ie_length = 0; + rc = usf_enc_ie_ident(usf, ie, ie_clrt_tbl); + + return(rc); +} + + +/* + * Encode a broadband bearer capability information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_bbcp(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + u_char c; + + ATM_DEBUG2("usf_enc_ie_bbcp: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + ie->ie_length = 0; + + /* + * Encode the broadband bearer class + */ + if (ie->ie_bbcp_bearer_class == T_ATM_ABSENT) + return(0); + c = ie->ie_bbcp_bearer_class & UNI_IE_BBCP_BC_MASK; + if (ie->ie_bbcp_bearer_class != UNI_IE_BBCP_BC_BCOB_X) + c |= UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + + /* + * If the broadband bearer class was X, the next + * byte has the traffic type and timing requirements + */ + if (ie->ie_bbcp_bearer_class == UNI_IE_BBCP_BC_BCOB_X) { + c = ((ie->ie_bbcp_traffic_type & UNI_IE_BBCP_TT_MASK) << + UNI_IE_BBCP_TT_SHIFT) + + (ie->ie_bbcp_timing_req & + UNI_IE_BBCP_TR_MASK) + + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + } + + /* + * Encode the clipping and user plane connection configuration + */ + c = ((ie->ie_bbcp_clipping & UNI_IE_BBCP_SC_MASK) << + UNI_IE_BBCP_SC_SHIFT) + + (ie->ie_bbcp_conn_config & + UNI_IE_BBCP_CC_MASK) + + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + + return(0); +} + + +/* + * Encode a broadband high layer information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_bhli(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int i, rc; + u_int type; + + ATM_DEBUG2("usf_enc_ie_bhli: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + ie->ie_length = 0; + + /* + * Encode the high layer information type + */ + if (ie->ie_bhli_type == T_ATM_ABSENT) + return(0); + type = ie->ie_bhli_type | UNI_IE_EXT_BIT; + rc = usf_ext(usf, &type); + if (rc) + return(rc); + ie->ie_length++; + + /* + * What comes next depends on the type + */ + switch (ie->ie_bhli_type) { + case UNI_IE_BHLI_TYPE_ISO: + case UNI_IE_BHLI_TYPE_USER: + /* + * ISO or user-specified parameters -- take the + * length of information from the IE length + */ + for (i=0; i<ie->ie_length-1; i++) { + rc = usf_byte(usf, &ie->ie_bhli_info[i]); + if (rc) + return(rc); + ie->ie_length++; + } + break; + case UNI_IE_BHLI_TYPE_HLP: + /* + * Make sure the IE is long enough for the high + * layer profile information, then get it + */ + if (usf->usf_sig->us_proto != ATM_SIG_UNI30) + return (EINVAL); + for (i=0; i<UNI_IE_BHLI_HLP_LEN; i++) { + rc = usf_byte(usf, &ie->ie_bhli_info[i]); + if (rc) + return(rc); + ie->ie_length++; + } + break; + case UNI_IE_BHLI_TYPE_VSA: + /* + * Make sure the IE is long enough for the vendor- + * specific application information, then get it + */ + for (i=0; i<UNI_IE_BHLI_VSA_LEN; i++) { + rc = usf_byte(usf, &ie->ie_bhli_info[i]); + if (rc) + return(rc); + ie->ie_length++; + } + break; + default: + return(EINVAL); + } + + return(0); +} + + +/* + * Encode a broadband low layer information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_blli(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + u_char c; + int rc; + u_int ipi; + + ATM_DEBUG2("usf_enc_ie_blli: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + ie->ie_length = 0; + + /* + * Encode paramteters for whichever protocol layers the + * user specified + */ + + /* + * Layer 1 information + */ + if (ie->ie_blli_l1_id && ie->ie_blli_l1_id != T_ATM_ABSENT) { + c = (UNI_IE_BLLI_L1_ID << UNI_IE_BLLI_LID_SHIFT) + + (ie->ie_blli_l1_id & + UNI_IE_BLLI_LP_MASK) + + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + } + + /* + * Layer 2 information + */ + if (ie->ie_blli_l2_id && ie->ie_blli_l2_id != T_ATM_ABSENT) { + c = (UNI_IE_BLLI_L2_ID << UNI_IE_BLLI_LID_SHIFT) + + (ie->ie_blli_l2_id & + UNI_IE_BLLI_LP_MASK); + + switch (ie->ie_blli_l2_id) { + case UNI_IE_BLLI_L2P_X25L: + case UNI_IE_BLLI_L2P_X25M: + case UNI_IE_BLLI_L2P_HDLC1: + case UNI_IE_BLLI_L2P_HDLC2: + case UNI_IE_BLLI_L2P_HDLC3: + case UNI_IE_BLLI_L2P_Q922: + case UNI_IE_BLLI_L2P_ISO7776: + /* + * Write the Layer 2 type + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + + /* + * Encode the Layer 2 mode + */ + if (ie->ie_blli_l2_mode) { + c = (ie->ie_blli_l2_mode & + UNI_IE_BLLI_L2MODE_MASK) << + UNI_IE_BLLI_L2MODE_SHIFT; + if (!ie->ie_blli_l2_window) + c |= UNI_IE_EXT_BIT; + + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + } + + /* + * Encode the Layer 2 window size + */ + if (ie->ie_blli_l2_window) { + c = (ie->ie_blli_l2_window & + UNI_IE_EXT_MASK) + + UNI_IE_EXT_BIT; + + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + } + break; + case UNI_IE_BLLI_L2P_USER: + /* + * Write the Layer 2 type + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + + /* + * Encode the user-specified layer 2 info + */ + c = (ie->ie_blli_l2_user_proto & + UNI_IE_EXT_MASK) + + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + break; + default: + /* + * Write the Layer 2 type + */ + c |= UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + break; + } + } + + /* + * Layer 3 information + */ + if (ie->ie_blli_l3_id && ie->ie_blli_l3_id != T_ATM_ABSENT) { + /* + * Encode the layer 3 protocol ID + */ + c = (UNI_IE_BLLI_L3_ID << UNI_IE_BLLI_LID_SHIFT) + + (ie->ie_blli_l3_id & + UNI_IE_BLLI_LP_MASK); + + /* + * Process other fields based on protocol ID + */ + switch(ie->ie_blli_l3_id) { + case UNI_IE_BLLI_L3P_X25: + case UNI_IE_BLLI_L3P_ISO8208: + case UNI_IE_BLLI_L3P_ISO8878: + /* + * Write the protocol ID + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + + if (ie->ie_blli_l3_mode || + ie->ie_blli_l3_packet_size || + ie->ie_blli_l3_window) { + c = (ie->ie_blli_l3_mode & + UNI_IE_BLLI_L3MODE_MASK) << + UNI_IE_BLLI_L3MODE_SHIFT; + if (!ie->ie_blli_l3_packet_size && + !ie->ie_blli_l3_window) + c |= UNI_IE_EXT_BIT; + + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + } + + if (ie->ie_blli_l3_packet_size || + ie->ie_blli_l3_window) { + c = ie->ie_blli_l3_packet_size & + UNI_IE_BLLI_L3PS_MASK; + if (!ie->ie_blli_l3_window) + c |= UNI_IE_EXT_BIT; + + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + } + + if (ie->ie_blli_l3_window) { + c = (ie->ie_blli_l3_window & + UNI_IE_EXT_MASK) + + UNI_IE_EXT_BIT; + + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + } + break; + case UNI_IE_BLLI_L3P_USER: + /* + * Write the protocol ID + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + + /* + * Encode the user-specified protocol info + */ + c = (ie->ie_blli_l3_user_proto & + UNI_IE_EXT_MASK) + + UNI_IE_EXT_BIT; + + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + break; + case UNI_IE_BLLI_L3P_ISO9577: + /* + * Write the protocol ID + */ + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + + /* + * Encode the IPI + */ + ipi = ie->ie_blli_l3_ipi << + UNI_IE_BLLI_L3IPI_SHIFT; + rc = usf_ext(usf, &ipi); + if (rc) + return(rc); + ie->ie_length += 2; + + if (ie->ie_blli_l3_ipi == + UNI_IE_BLLI_L3IPI_SNAP) { + c = UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + rc = usf_byte(usf, + &ie->ie_blli_l3_oui[0]); + if (rc) + return(rc); + + rc = usf_byte(usf, + &ie->ie_blli_l3_oui[1]); + if (rc) + return(rc); + + rc = usf_byte(usf, + &ie->ie_blli_l3_oui[2]); + if (rc) + return(rc); + + rc = usf_byte(usf, + &ie->ie_blli_l3_pid[0]); + if (rc) + return(rc); + + rc = usf_byte(usf, + &ie->ie_blli_l3_pid[1]); + if (rc) + return(rc); + + ie->ie_length += 6; + } + break; + default: + /* + * Write the layer 3 protocol ID + */ + c |= UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + break; + } + } + + return(0); +} + + +/* + * Encode a call state information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_clst(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + u_char c; + + ATM_DEBUG2("usf_enc_ie_clst: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + c = ie->ie_clst_state & UNI_IE_CLST_STATE_MASK; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length = 1; + + return(0); +} + + +/* + * Encode a called party number information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_cdad(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + u_char c; + int rc; + + ATM_DEBUG2("usf_enc_ie_cdad: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + /* + * Encode the numbering plan + */ + switch(ie->ie_cdad_addr.address_format) { + case T_ATM_E164_ADDR: + c = UNI_IE_CDAD_PLAN_E164 + + (UNI_IE_CDAD_TYPE_INTL + << UNI_IE_CDAD_TYPE_SHIFT); + ie->ie_length = sizeof(Atm_addr_e164) + 1; + break; + case T_ATM_ENDSYS_ADDR: + c = UNI_IE_CDAD_PLAN_NSAP + + (UNI_IE_CDAD_TYPE_UNK + << UNI_IE_CDAD_TYPE_SHIFT); + ie->ie_length = sizeof(Atm_addr_nsap) + 1; + break; + default: + return(EINVAL); + } + c |= UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Encode the ATM address + */ + rc = usf_enc_atm_addr(usf, &ie->ie_cdad_addr); + + return(rc); +} + + +/* + * Encode a called party subaddress information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_cdsa(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + u_char c; + int rc; + + /* + * Encode the subaddress type + */ + switch(ie->ie_cdsa_addr.address_format) { + case T_ATM_ENDSYS_ADDR: + c = UNI_IE_CDSA_TYPE_AESA << UNI_IE_CDSA_TYPE_SHIFT; + ie->ie_length = sizeof(Atm_addr_nsap) + 1; + break; + default: + return(EINVAL); + } + c |= UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Encode the ATM address + */ + rc = usf_enc_atm_addr(usf, &ie->ie_cdsa_addr); + + return(rc); +} + + +/* + * Encode a calling party number information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_cgad(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + u_char c; + int rc; + + ATM_DEBUG2("usf_enc_ie_cgad: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + /* + * Encode the numbering plan + */ + switch(ie->ie_cgad_addr.address_format) { + case T_ATM_E164_ADDR: + c = UNI_IE_CGAD_PLAN_E164 + + (UNI_IE_CGAD_TYPE_INTL + << UNI_IE_CGAD_TYPE_SHIFT) + + UNI_IE_EXT_BIT; + ie->ie_length = sizeof(Atm_addr_e164) + 1; + break; + case T_ATM_ENDSYS_ADDR: + c = UNI_IE_CGAD_PLAN_NSAP + + (UNI_IE_CGAD_TYPE_UNK + << UNI_IE_CGAD_TYPE_SHIFT) + + UNI_IE_EXT_BIT; + ie->ie_length = sizeof(Atm_addr_nsap) + 1; + break; + default: + return(EINVAL); + } + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Encode the presentation and screening indicators + */ +#ifdef NOTDEF + c = ((ie->ie_cgad_pres_ind & UNI_IE_CGAD_PRES_MASK) + << UNI_IE_CGAD_PRES_SHIFT) + + (ie->ie_cgad_screen_ind & + UNI_IE_CGAD_SCR_MASK) + + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); +#endif + + + /* + * Encode the ATM address + */ + rc = usf_enc_atm_addr(usf, &ie->ie_cgad_addr); + + return(rc); +} + + +/* + * Encode a calling party subaddress information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_cgsa(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + u_char c; + int rc; + + /* + * Encode the subaddress type + */ + switch(ie->ie_cgsa_addr.address_format) { + case T_ATM_ENDSYS_ADDR: + c = UNI_IE_CGSA_TYPE_AESA << UNI_IE_CGSA_TYPE_SHIFT; + ie->ie_length = sizeof(Atm_addr_nsap) + 1; + break; + default: + return(EINVAL); + } + c |= UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + /* + * Encode the ATM address + */ + rc = usf_enc_atm_addr(usf, &ie->ie_cgsa_addr); + + return(rc); +} + + +/* + * Encode a cause information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_caus(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int i, rc; + u_char c; + + ATM_DEBUG2("usf_enc_ie_caus: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + ie->ie_length = 0; + + /* + * Encode the cause location + */ + c = (ie->ie_caus_loc & UNI_IE_CAUS_LOC_MASK) | UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + + /* + * Encode the cause value + */ + c = ie->ie_caus_cause | UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length++; + + /* + * Encode any included diagnostics + */ + for (i = 0; i < ie->ie_caus_diag_len && + i < sizeof(ie->ie_caus_diagnostic); + i++) { + rc = usf_byte(usf, &ie->ie_caus_diagnostic[i]); + if (rc) + return(rc); + ie->ie_length++; + } + + return(0); +} + + +/* + * Encode a conection identifier information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_cnid(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + u_char c; + + ATM_DEBUG2("usf_enc_ie_cnid: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + c = ((ie->ie_cnid_vp_sig & UNI_IE_CNID_VPSIG_MASK) + << UNI_IE_CNID_VPSIG_SHIFT) + + (ie->ie_cnid_pref_excl & UNI_IE_CNID_PREX_MASK) + + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + + rc = usf_short(usf, &ie->ie_cnid_vpci); + if (rc) + return(rc); + rc = usf_short(usf, &ie->ie_cnid_vci); + if (rc) + return(rc); + + ie->ie_length = 5; + return(0); +} + + +/* + * Encode a quality of service parameters information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_qosp(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + + ATM_DEBUG2("usf_enc_ie_qosp: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + /* + * Encode forward QoS class + */ + if (ie->ie_qosp_fwd_class == T_ATM_ABSENT || + ie->ie_qosp_bkwd_class == T_ATM_ABSENT) + return(0); + rc = usf_byte(usf, &ie->ie_qosp_fwd_class); + if (rc) + return(rc); + + /* + * Encode backward QoS class + */ + rc = usf_byte(usf, &ie->ie_qosp_bkwd_class); + + ie->ie_length = 2; + return(rc); +} + + +/* + * Encode a broadband repeat indicator information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_brpi(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + u_char c; + + ATM_DEBUG2("usf_enc_ie_brpi: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + /* + * Encode the repeat indicator + */ + c = ie->ie_brpi_ind + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + + return(rc); +} + + +/* + * Encode a restart indicator information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_rsti(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + u_char c; + + ATM_DEBUG2("usf_enc_ie_rsti: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + /* + * Encode the restart class + */ + c = (ie->ie_rsti_class & UNI_IE_RSTI_CLASS_MASK) | + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + ie->ie_length = 1; + + return(rc); +} + + +/* + * Encode a broadband sending complete information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a broadband sending complete IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_bsdc(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int rc; + u_char c; + + ATM_DEBUG2("usf_enc_ie_bsdc: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + /* + * Encode the sending complete indicator + */ + c = UNI_IE_BSDC_IND | UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + ie->ie_length = 1; + + return(rc); +} + + +/* + * Encode a transit network selection information element + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a transit network selection rate IE structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_trnt(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + int i, rc; + u_char c; + + ATM_DEBUG2("usf_enc_ie_trnt: usf=0x%x, ie=0x%x\n", + (int)usf, (int)ie); + + /* + * Encode the sending complete indicator + */ + c = ((ie->ie_trnt_id_type & UNI_IE_TRNT_IDT_MASK) << + UNI_IE_TRNT_IDT_SHIFT) + + (ie->ie_trnt_id_plan & UNI_IE_TRNT_IDP_MASK) + + UNI_IE_EXT_BIT; + rc = usf_byte(usf, &c); + if (rc) + return(rc); + ie->ie_length = 1; + + /* + * Encode the network identification + */ + for (i=0; i<ie->ie_trnt_id_len; i++) { + rc = usf_byte(usf, &ie->ie_trnt_id[i]); + if (rc) + return(rc); + ie->ie_length++; + } + + return(rc); +} + + +/* + * Encode an unsupported IE type + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to an IE structure + * + * Returns: + * 0 success + * + */ +static int +usf_enc_ie_uimp(usf, ie) + struct usfmt *usf; + struct ie_generic *ie; +{ + return(0); +} + + +/* + * Encode an information element using field identifiers + * + * The AAL parameters and ATM user cell rate IEs are formatted + * with a one-byte identifier preceeding each field. The routine + * encodes these IEs by using a table which relates the field + * identifiers with the fields in the appropriate IE structure. + * + * Arguments: + * usf pointer to a unisig formatting structure + * ie pointer to a cell rate IE structure + * tbl pointer to an IE decoding table + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_ie_ident(usf, ie, tbl) + struct usfmt *usf; + struct ie_generic *ie; + struct ie_decode_tbl *tbl; +{ + int i, len, rc; + char *cp; + u_int8_t cv; + u_int16_t sv; + u_int32_t iv; + + ATM_DEBUG3("usf_enc_ie_ident: usf=0x%x, ie=0x%x, tbl=0x%x\n", + (int)usf, (int)ie, (int)tbl); + + /* + * Scan through the IE table + */ + len = 0; + for (i=0; tbl[i].ident; i++) { + /* + * Check whether to send the field + */ + cp = (char *) ((int)ie + tbl[i].f_offs); + if (tbl[i].len == 0) { + if ((*cp == T_NO || *cp == T_ATM_ABSENT)) + continue; + } else { + switch (tbl[i].f_size) { + case 1: + if (*(int8_t *)cp == T_ATM_ABSENT) + continue; + break; + case 2: + if (*(int16_t *)cp == T_ATM_ABSENT) + continue; + break; + case 4: + if (*(int32_t *)cp == T_ATM_ABSENT) + continue; + break; + default: +badtbl: + log(LOG_ERR, + "uni encode: id=%d,len=%d,off=%d,size=%d\n", + tbl[i].ident, tbl[i].len, + tbl[i].f_offs, tbl[i].f_size); + return (EFAULT); + } + } + + /* + * Encode the field identifier + */ + rc = usf_byte(usf, &tbl[i].ident); + if (rc) + return(rc); + len++; + + /* + * Encode the field value + */ + switch (tbl[i].len) { + case 0: + break; + case 1: + switch (tbl[i].f_size) { + case 1: + cv = *(u_int8_t *)cp; + break; + case 2: + cv = *(u_int16_t *)cp; + break; + case 4: + cv = *(u_int32_t *)cp; + break; + default: + goto badtbl; + } + rc = usf_byte(usf, &cv); + break; + + case 2: + switch (tbl[i].f_size) { + case 2: + sv = *(u_int16_t *)cp; + break; + case 4: + sv = *(u_int32_t *)cp; + break; + default: + goto badtbl; + } + rc = usf_short(usf, &sv); + break; + + case 3: + switch (tbl[i].f_size) { + case 4: + iv = *(u_int32_t *)cp; + break; + default: + goto badtbl; + } + rc = usf_int3(usf, &iv); + break; + + case 4: + switch (tbl[i].f_size) { + case 4: + iv = *(u_int32_t *)cp; + break; + default: + goto badtbl; + } + rc = usf_int(usf, &iv); + break; + + default: + goto badtbl; + } + + len += tbl[i].len; + + if (rc) + return(rc); + } + + ie->ie_length = len; + return(0); +} + + +/* + * Encode an ATM address + * + * Arguments: + * usf pointer to a unisig formatting structure + * addr pointer to an ATM address structure. The address + * type must already be set correctly. + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +usf_enc_atm_addr(usf, addr) + struct usfmt *usf; + Atm_addr *addr; +{ + int len, rc; + u_char *cp; + + /* + * Check the address type + */ + switch (addr->address_format) { + case T_ATM_E164_ADDR: + cp = (u_char *) addr->address; + len = sizeof(Atm_addr_e164); + break; + case T_ATM_ENDSYS_ADDR: + cp = (u_char *) addr->address; + len = sizeof(Atm_addr_nsap); + break; + default: + return(EINVAL); + } + + /* + * Get the address bytes + */ + while (len) { + rc = usf_byte(usf, cp); + if (rc) + return(rc); + len--; + cp++; + } + + return(0); +} diff --git a/sys/netatm/uni/unisig_if.c b/sys/netatm/uni/unisig_if.c new file mode 100644 index 0000000..784b6c5 --- /dev/null +++ b/sys/netatm/uni/unisig_if.c @@ -0,0 +1,1012 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: unisig_if.c,v 1.12 1998/07/30 22:36:57 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * System interface module + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_if.c,v 1.12 1998/07/30 22:36:57 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/ipatm/ipatm_var.h> +#include <netatm/ipatm/ipatm_serv.h> +#include <netatm/uni/uniip_var.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/unisig.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/unisig_msg.h> + + +/* + * Global variables + */ +struct sp_info unisig_vcpool = { + "unisig vcc pool", /* si_name */ + sizeof(struct unisig_vccb), /* si_blksiz */ + 10, /* si_blkcnt */ + 50 /* si_maxallow */ +}; + +struct sp_info unisig_msgpool = { + "unisig message pool", /* si_name */ + sizeof(struct unisig_msg), /* si_blksiz */ + 10, /* si_blkcnt */ + 50 /* si_maxallow */ +}; + +struct sp_info unisig_iepool = { + "unisig ie pool", /* si_name */ + sizeof(struct ie_generic), /* si_blksiz */ + 10, /* si_blkcnt */ + 50 /* si_maxallow */ +}; + + +/* + * Local functions + */ +static int unisig_attach __P((struct sigmgr *, struct atm_pif *)); +static int unisig_detach __P((struct atm_pif *)); +static int unisig_setup __P((Atm_connvc *, int *)); +static int unisig_release __P((struct vccb *, int *)); +static int unisig_accept __P((struct vccb *, int *)); +static int unisig_reject __P((struct vccb *, int *)); +static int unisig_abort __P((struct vccb *)); +static int unisig_ioctl __P((int, caddr_t, caddr_t)); + + +/* + * Local variables + */ +static struct sigmgr unisig_mgr30 = { + NULL, + ATM_SIG_UNI30, + NULL, + unisig_attach, + unisig_detach, + unisig_setup, + unisig_accept, + unisig_reject, + unisig_release, + unisig_free, + unisig_ioctl +}; + +static struct sigmgr unisig_mgr31 = { + NULL, + ATM_SIG_UNI31, + NULL, + unisig_attach, + unisig_detach, + unisig_setup, + unisig_accept, + unisig_reject, + unisig_release, + unisig_free, + unisig_ioctl +}; + + +/* + * Initialize UNISIG processing + * + * This will be called during module loading. We'll just register + * the UNISIG protocol descriptor and wait for a UNISIG ATM interface + * to come online. + * + * Arguments: + * none + * + * Returns: + * 0 startup was successful + * errno startup failed - reason indicated + * + */ +int +unisig_start() +{ + int err = 0; + + /* + * Verify software version + */ + if (atm_version != ATM_VERSION) { + log(LOG_ERR, "version mismatch: unisig=%d.%d kernel=%d.%d\n", + ATM_VERS_MAJ(ATM_VERSION), + ATM_VERS_MIN(ATM_VERSION), + ATM_VERS_MAJ(atm_version), + ATM_VERS_MIN(atm_version)); + return (EINVAL); + } + + /* + * Register ourselves with system + */ + err = atm_sigmgr_register(&unisig_mgr30); + if (err) + goto done; + + err = atm_sigmgr_register(&unisig_mgr31); + +done: + return (err); +} + + +/* + * Halt UNISIG processing + * + * This should be called just prior to unloading the module from + * memory. All UNISIG interfaces must be deregistered before the + * protocol can be shutdown. + * + * Arguments: + * none + * + * Returns: + * 0 startup was successful + * errno startup failed - reason indicated + * + */ +int +unisig_stop() +{ + int err = 0; + int s = splnet(); + + + /* + * Any protocol instances still registered? + */ + if ((unisig_mgr30.sm_prinst != NULL) || + (unisig_mgr31.sm_prinst != NULL)) { + + /* Yes, can't stop now */ + err = EBUSY; + goto done; + } + + /* + * De-register from system + */ + (void) atm_sigmgr_deregister(&unisig_mgr30); + (void) atm_sigmgr_deregister(&unisig_mgr31); + + /* + * Free up our storage pools + */ + atm_release_pool(&unisig_vcpool); + atm_release_pool(&unisig_msgpool); + atm_release_pool(&unisig_iepool); + +done: + (void) splx(s); + return (err); +} + + +/* + * Attach a UNISIG-controlled interface + * + * Each ATM physical interface must be attached with the signalling + * manager for the interface's signalling protocol (via the + * atm_sigmgr_attach function). This function will handle the + * attachment for UNISIG-controlled interfaces. A new UNISIG protocol + * instance will be created and then we'll just sit around waiting for + * status or connection requests. + * + * Function must be called at splnet. + * + * Arguments: + * smp pointer to UNISIG signalling manager control block + * pip pointer to ATM physical interface control block + * + * Returns: + * 0 attach successful + * errno attach failed - reason indicated + * + */ +static int +unisig_attach(smp, pip) + struct sigmgr *smp; + struct atm_pif *pip; +{ + int err = 0, s; + struct unisig *usp = NULL; + + ATM_DEBUG2("unisig_attach: smp=%x, pip=%x\n", smp, pip); + + /* + * Allocate UNISIG protocol instance control block + */ + usp = (struct unisig *) + KM_ALLOC(sizeof(struct unisig), M_DEVBUF, M_NOWAIT); + if (usp == NULL) { + err = ENOMEM; + goto done; + } + KM_ZERO(usp, sizeof(struct unisig)); + + /* + * Set state in UNISIG protocol instance control block + */ + usp->us_state = UNISIG_NULL; + usp->us_proto = smp->sm_proto; + + /* + * Set initial call reference allocation value + */ + usp->us_cref = 1; + + /* + * Link instance into manager's chain + */ + LINK2TAIL((struct siginst *)usp, struct siginst, smp->sm_prinst, + si_next); + + /* + * Link in interface + */ + usp->us_pif = pip; + s = splimp(); + pip->pif_sigmgr = smp; + pip->pif_siginst = (struct siginst *) usp; + (void) splx(s); + + /* + * Clear our ATM address. The address will be set by user + * command or by registration via ILMI. + */ + usp->us_addr.address_format = T_ATM_ABSENT; + usp->us_addr.address_length = 0; + usp->us_subaddr.address_format = T_ATM_ABSENT; + usp->us_subaddr.address_length = 0; + + /* + * Set pointer to IP + */ + usp->us_ipserv = &uniip_ipserv; + + /* + * Kick-start the UNISIG protocol + */ + UNISIG_TIMER(usp, 0); + + /* + * Log the fact that we've attached + */ + log(LOG_INFO, "unisig: attached to interface %s%d\n", + pip->pif_name, pip->pif_unit); + +done: + /* + * Reset our work if attach fails + */ + if (err) { + if (usp) { + UNISIG_CANCEL(usp); + UNLINK((struct siginst *)usp, struct siginst, + smp->sm_prinst, si_next); + KM_FREE(usp, sizeof(struct unisig), M_DEVBUF); + } + s = splimp(); + pip->pif_sigmgr = NULL; + pip->pif_siginst = NULL; + (void) splx(s); + } + + return (err); +} + + +/* + * Detach a UNISIG-controlled interface + * + * Each ATM physical interface may be detached from its signalling + * manager (via the atm_sigmgr_detach function). This function will + * handle the detachment for all UNISIG-controlled interfaces. All + * circuits will be immediately terminated. + * + * Function must be called at splnet. + * + * Arguments: + * pip pointer to ATM physical interface control block + * + * Returns: + * 0 detach successful + * errno detach failed - reason indicated + * + */ +static int +unisig_detach(pip) + struct atm_pif *pip; +{ + struct unisig *usp; + int err; + + ATM_DEBUG1("unisig_detach: pip=0x%x\n", pip); + + /* + * Get UNISIG protocol instance + */ + usp = (struct unisig *)pip->pif_siginst; + + /* + * Return an error if we're already detaching + */ + if (usp->us_state == UNISIG_DETACH) { + return(EALREADY); + } + + /* + * Pass the detach event to the signalling manager + * state machine + */ + err = unisig_sigmgr_state(usp, UNISIG_SIGMGR_DETACH, + (KBuffer *)0); + + /* + * Log the fact that we've detached + */ + if (!err) + log(LOG_INFO, "unisig: detached from interface %s%d\n", + pip->pif_name, pip->pif_unit); + + return (0); +} + + +/* + * Open a UNISIG ATM Connection + * + * All service user requests to open a VC connection (via + * atm_open_connection) over an ATM interface attached to the UNISIG + * signalling manager are handled here. + * + * Function will be called at splnet. + * + * Arguments: + * cvp pointer to user's requested connection parameters + * errp pointer to an int for extended error information + * + * Returns: + * CALL_PROCEEDING connection establishment is in progress + * CALL_FAILED connection establishment failed + * CALL_CONNECTED connection has been successfully established + * + */ +static int +unisig_setup(cvp, errp) + Atm_connvc *cvp; + int *errp; +{ + struct atm_pif *pip = cvp->cvc_attr.nif->nif_pif; + struct unisig *usp = (struct unisig *)pip->pif_siginst; + int rc = 0; + + ATM_DEBUG1("unisig_setup: cvp=0x%x\n", cvp); + + /* + * Intialize the returned error code + */ + *errp = 0; + + /* + * Open the connection + */ + switch (cvp->cvc_attr.called.addr.address_format) { + case T_ATM_PVC_ADDR: + /* + * Create a PVC + */ + *errp = unisig_open_vcc(usp, cvp); + rc = (*errp ? CALL_FAILED : CALL_CONNECTED); + break; + + case T_ATM_ENDSYS_ADDR: + case T_ATM_E164_ADDR: + + /* + * Create an SVC + */ + *errp = unisig_open_vcc(usp, cvp); + rc = (*errp ? CALL_FAILED : CALL_PROCEEDING); + break; + + default: + *errp = EPROTONOSUPPORT; + rc = CALL_FAILED; + } + + return (rc); +} + + +/* + * Close a UNISIG ATM Connection + * + * All service user requests to terminate a previously open VC + * connection (via the atm_close_connection function), which is running + * over an interface attached to the UNISIG signalling manager, are + * handled here. + * + * Function will be called at splnet. + * + * Arguments: + * vcp pointer to connection's VC control block + * errp pointer to an int for extended error information + * + * Returns: + * CALL_PROCEEDING connection termination is in progress + * CALL_FAILED connection termination failed + * CALL_CLEARED connection has been successfully terminated + * + */ +static int +unisig_release(vcp, errp) + struct vccb *vcp; + int *errp; +{ + int rc = 0; + struct atm_pif *pip = vcp->vc_pif; + struct unisig *usp = (struct unisig *)pip->pif_siginst; + + ATM_DEBUG1("unisig_release: vcp=0x%x\n", vcp); + + /* + * Initialize returned error code + */ + *errp = 0; + + /* + * Validate the connection type (PVC or SVC) + */ + if (!(vcp->vc_type & (VCC_PVC | VCC_SVC))) { + *errp = EPROTONOSUPPORT; + return(CALL_FAILED); + } + + /* + * Close the VCCB + */ + *errp = unisig_close_vcc(usp, (struct unisig_vccb *)vcp); + + /* + * Set the return code + */ + if (*errp) { + rc = CALL_FAILED; + } else if (vcp->vc_sstate == UNI_NULL || + vcp->vc_sstate == UNI_FREE) { + rc = CALL_CLEARED; + } else { + rc = CALL_PROCEEDING; + } + + return (rc); +} + + +/* + * Accept a UNISIG Open from a remote host + * + * A user calls this routine (via the atm_accept_call function) + * after it is notified that an open request was received for it. + * + * Function will be called at splnet. + * + * Arguments: + * vcp pointer to user's VCCB + * errp pointer to an int for extended error information + * + * Returns: + * CALL_PROCEEDING connection establishment is in progress + * CALL_FAILED connection establishment failed + * CALL_CONNECTED connection has been successfully established + * + */ +static int +unisig_accept(vcp, errp) + struct vccb *vcp; + int *errp; +{ + struct unisig_vccb *uvp = (struct unisig_vccb *)vcp; + struct atm_pif *pip = uvp->uv_pif; + struct unisig *usp = (struct unisig *)pip->pif_siginst; + + ATM_DEBUG1("unisig_accept: vcp=0x%x\n", vcp); + + /* + * Initialize the returned error code + */ + *errp = 0; + + /* + * Return an error if we're detaching + */ + if (usp->us_state == UNISIG_DETACH) { + *errp = ENETDOWN; + goto free; + } + + /* + * Return an error if we lost the connection + */ + if (uvp->uv_sstate == UNI_FREE) { + *errp = ENETDOWN; + goto free; + } + + /* + * Pass the acceptance to the VC state machine + */ + *errp = unisig_vc_state(usp, uvp, UNI_VC_ACCEPT_CALL, + (struct unisig_msg *) 0); + if (*errp) + goto failed; + + return(CALL_PROCEEDING); + +failed: + /* + * On error, free the VCCB and return CALL_FAILED + */ + +free: + uvp->uv_sstate = UNI_FREE; + uvp->uv_ustate = VCCU_CLOSED; + DEQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq); + unisig_free((struct vccb *)uvp); + + return(CALL_FAILED); +} + + +/* + * Reject a UNISIG Open from a remote host + * + * A user calls this routine (via the atm_reject_call function) + * after it is notified that an open request was received for it. + * + * Function will be called at splnet. + * + * Arguments: + * uvp pointer to user's VCCB + * errp pointer to an int for extended error information + * + * Returns: + * CALL_CLEARED call request rejected + * CALL_FAILED call rejection failed + * + */ +static int +unisig_reject(vcp, errp) + struct vccb *vcp; + int *errp; +{ + struct unisig_vccb *uvp = (struct unisig_vccb *)vcp; + struct atm_pif *pip = uvp->uv_pif; + struct unisig *usp = (struct unisig *)pip->pif_siginst; + + ATM_DEBUG1("unisig_reject: uvp=0x%x\n", uvp); + + /* + * Initialize the returned error code + */ + *errp = 0; + + + /* + * Return an error if we're detaching + */ + if (usp->us_state == UNISIG_DETACH) { + *errp = ENETDOWN; + goto failed; + } + + /* + * Call the VC state machine + */ + *errp = unisig_vc_state(usp, uvp, UNI_VC_REJECT_CALL, + (struct unisig_msg *) 0); + if (*errp) + goto failed; + + return(CALL_CLEARED); + +failed: + /* + * On error, free the VCCB and return CALL_FAILED + */ + uvp->uv_sstate = UNI_FREE; + uvp->uv_ustate = VCCU_CLOSED; + DEQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq); + (void) unisig_free((struct vccb *)uvp); + return(CALL_FAILED); +} + + +/* + * Abort a UNISIG ATM Connection + * + * All (non-user) requests to abort a previously open VC connection (via + * the atm_abort_connection function), which is running over an + * interface attached to the UNISIG signalling manager, are handled here. + * The VCC owner will be notified of the request, in order to initiate + * termination of the connection. + * + * Function will be called at splnet. + * + * Arguments: + * vcp pointer to connection's VC control block + * + * Returns: + * 0 connection release was successful + * errno connection release failed - reason indicated + * + */ +static int +unisig_abort(vcp) + struct vccb *vcp; +{ + + ATM_DEBUG1("unisig_abort: vcp=0x%x\n", (int)vcp); + + /* + * Only abort once + */ + if (vcp->vc_ustate == VCCU_ABORT) { + return (EALREADY); + } + + /* + * Cancel any timer that might be running + */ + UNISIG_VC_CANCEL(vcp); + + /* + * Set immediate timer to schedule connection termination + */ + vcp->vc_ustate = VCCU_ABORT; + UNISIG_VC_TIMER(vcp, 0); + + return (0); +} + + +/* + * Free UNISIG ATM connection resources + * + * All service user requests to free the resources of a closed VCC + * connection (via the atm_free_connection function), which is running + * over an interface attached to the UNISIG signalling manager, are + *handled here. + * + * Function will be called at splnet. + * + * Arguments: + * vcp pointer to connection's VC control block + * + * Returns: + * 0 connection free was successful + * errno connection free failed - reason indicated + * + */ +int +unisig_free(vcp) + struct vccb *vcp; +{ + struct atm_pif *pip = vcp->vc_pif; + struct unisig *usp = (struct unisig *)pip->pif_siginst; + + ATM_DEBUG1("unisig_free: vcp = 0x%x\n", vcp); + + /* + * Make sure VCC has been closed + */ + if ((vcp->vc_ustate != VCCU_CLOSED && + vcp->vc_ustate != VCCU_ABORT) || + vcp->vc_sstate != UNI_FREE) { + ATM_DEBUG2("unisig_free: bad state, sstate=%d, ustate=%d\n", + vcp->vc_sstate, vcp->vc_ustate); + return(EEXIST); + } + + /* + * Remove VCCB from protocol queue + */ + DEQUEUE(vcp, struct vccb, vc_sigelem, usp->us_vccq); + + /* + * Free VCCB storage + */ + vcp->vc_ustate = VCCU_NULL; + vcp->vc_sstate = UNI_NULL; + atm_free((caddr_t)vcp); + + /* + * If we're detaching and this was the last VCC queued, + * get rid of the protocol instance + */ + if ((usp->us_state == UNISIG_DETACH) && + (Q_HEAD(usp->us_vccq, struct vccb) == NULL)) { + struct sigmgr *smp = pip->pif_sigmgr; + int s = splimp(); + + pip->pif_sigmgr = NULL; + pip->pif_siginst = NULL; + (void) splx(s); + + UNLINK((struct siginst *)usp, struct siginst, + smp->sm_prinst, si_next); + KM_FREE(usp, sizeof(struct unisig), M_DEVBUF); + } + + return (0); +} + + +/* + * UNISIG IOCTL support + * + * Function will be called at splnet. + * + * Arguments: + * code PF_ATM sub-operation code + * data pointer to code specific parameter data area + * arg1 pointer to code specific argument + * + * Returns: + * 0 request procesed + * errno error processing request - reason indicated + * + */ +static int +unisig_ioctl(code, data, arg1) + int code; + caddr_t data; + caddr_t arg1; +{ + struct atmdelreq *adp; + struct atminfreq *aip; + struct atmsetreq *asp; + struct unisig *usp; + struct unisig_vccb *uvp; + struct air_vcc_rsp rsp; + struct atm_pif *pip; + Atm_connection *cop; + u_int vpi, vci; + int err = 0, buf_len, i; + caddr_t buf_addr; + + ATM_DEBUG1("unisig_ioctl: code=%d\n", code); + + switch (code) { + + case AIOCS_DEL_PVC: + case AIOCS_DEL_SVC: + /* + * Delete a VCC + */ + adp = (struct atmdelreq *)data; + usp = (struct unisig *)arg1; + + /* + * Don't let a user close the UNISIG signalling VC + */ + vpi = adp->adr_pvc_vpi; + vci = adp->adr_pvc_vci; + if ((vpi == UNISIG_SIG_VPI && vci == UNISIG_SIG_VCI)) + return(EINVAL); + + /* + * Find requested VCC + */ + for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp; + uvp = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem)) { + if ((uvp->uv_vpi == vpi) && (uvp->uv_vci == vci)) + break; + } + if (uvp == NULL) + return (ENOENT); + + /* + * Check VCC type + */ + switch (code) { + case AIOCS_DEL_PVC: + if (!(uvp->uv_type & VCC_PVC)) { + return(EINVAL); + } + break; + case AIOCS_DEL_SVC: + if (!(uvp->uv_type & VCC_SVC)) { + return(EINVAL); + } + break; + } + + /* + * Schedule VCC termination + */ + unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr, + T_ATM_CAUSE_UNSPECIFIED_NORMAL); + err = unisig_abort((struct vccb *)uvp); + break; + + case AIOCS_INF_VCC: + /* + * Return VCC information + */ + aip = (struct atminfreq *)data; + usp = (struct unisig *)arg1; + + buf_addr = aip->air_buf_addr; + buf_len = aip->air_buf_len; + + /* + * Loop through the VCC queue + */ + for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp; + uvp = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem)) { + /* + * Make sure there's room in the user's buffer + */ + if (buf_len < sizeof(rsp)) { + err = ENOSPC; + break; + } + + /* + * Fill out the response struct for the VCC + */ + (void) sprintf(rsp.avp_intf, "%s%d", + usp->us_pif->pif_name, + usp->us_pif->pif_unit); + rsp.avp_vpi = uvp->uv_vpi; + rsp.avp_vci = uvp->uv_vci; + rsp.avp_type = uvp->uv_type; + rsp.avp_aal = uvp->uv_connvc->cvc_attr.aal.type; + rsp.avp_sig_proto = uvp->uv_proto; + cop = uvp->uv_connvc->cvc_conn; + if (cop) + rsp.avp_encaps = cop->co_mpx; + else + rsp.avp_encaps = 0; + rsp.avp_state = uvp->uv_sstate; + if (uvp->uv_connvc->cvc_flags & CVCF_CALLER) { + rsp.avp_daddr = uvp->uv_connvc->cvc_attr.called.addr; + } else { + rsp.avp_daddr = uvp->uv_connvc->cvc_attr.calling.addr; + } + rsp.avp_dsubaddr.address_format = T_ATM_ABSENT; + rsp.avp_dsubaddr.address_length = 0; + rsp.avp_ipdus = uvp->uv_ipdus; + rsp.avp_opdus = uvp->uv_opdus; + rsp.avp_ibytes = uvp->uv_ibytes; + rsp.avp_obytes = uvp->uv_obytes; + rsp.avp_ierrors = uvp->uv_ierrors; + rsp.avp_oerrors = uvp->uv_oerrors; + rsp.avp_tstamp = uvp->uv_tstamp; + KM_ZERO(rsp.avp_owners, + sizeof(rsp.avp_owners)); + for (i = 0; cop && i < sizeof(rsp.avp_owners); + cop = cop->co_next, + i += T_ATM_APP_NAME_LEN+1) { + strncpy(&rsp.avp_owners[i], + cop->co_endpt->ep_getname(cop->co_toku), + T_ATM_APP_NAME_LEN); + } + + /* + * Copy the response into the user's buffer + */ + if (err = copyout((caddr_t)&rsp, buf_addr, + sizeof(rsp))) + break; + buf_addr += sizeof(rsp); + buf_len -= sizeof(rsp); + } + + /* + * Update the buffer pointer and length + */ + aip->air_buf_addr = buf_addr; + aip->air_buf_len = buf_len; + break; + + case AIOCS_INF_ARP: + case AIOCS_INF_ASV: + case AIOCS_SET_ASV: + /* + * Get ARP table information or get/set ARP server address + */ + err = uniarp_ioctl(code, data, arg1); + break; + + case AIOCS_SET_PRF: + /* + * Set NSAP prefix + */ + asp = (struct atmsetreq *)data; + usp = (struct unisig *)arg1; + pip = usp->us_pif; + if (usp->us_addr.address_format != T_ATM_ABSENT) { + if (KM_CMP(asp->asr_prf_pref, usp->us_addr.address, + sizeof(asp->asr_prf_pref)) != 0) + err = EALREADY; + break; + } + usp->us_addr.address_format = T_ATM_ENDSYS_ADDR; + usp->us_addr.address_length = sizeof(Atm_addr_nsap); + KM_COPY(&pip->pif_macaddr, + ((Atm_addr_nsap *)usp->us_addr.address)->aan_esi, + sizeof(pip->pif_macaddr)); + KM_COPY((caddr_t) asp->asr_prf_pref, + &((Atm_addr_nsap *)usp->us_addr.address)->aan_afi, + sizeof(asp->asr_prf_pref)); + log(LOG_INFO, "uni: set address %s on interface %s\n", + unisig_addr_print(&usp->us_addr), + asp->asr_prf_intf); + + /* + * Pass event to signalling manager state machine + */ + err = unisig_sigmgr_state(usp, UNISIG_SIGMGR_ADDR_SET, + (KBuffer *) NULL); + + /* + * Clean up if there was an error + */ + if (err) { + usp->us_addr.address_format = T_ATM_ABSENT; + usp->us_addr.address_length = 0; + break; + } + + /* + * Inform ARP code of new address + */ + uniarp_ifaddr((struct siginst *)usp); + break; + + default: + err = EOPNOTSUPP; + } + + return (err); +} diff --git a/sys/netatm/uni/unisig_mbuf.c b/sys/netatm/uni/unisig_mbuf.c new file mode 100644 index 0000000..84c78fe --- /dev/null +++ b/sys/netatm/uni/unisig_mbuf.c @@ -0,0 +1,485 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: unisig_mbuf.c,v 1.6 1998/08/26 23:29:22 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Message buffer handling routines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_mbuf.c,v 1.6 1998/08/26 23:29:22 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/unisig_mbuf.h> +#include <netatm/uni/unisig_msg.h> + + +/* + * Initialize a unisig formatting structure + * + * Arguments: + * usf pointer to a unisig formatting structure + * usp pointer to a unisig protocol instance + * buf pointer to a buffer chain (decode only) + * op operation code (encode or decode) + * headroom headroom to leave in first buffer + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +usf_init(usf, usp, buf, op, headroom) + struct usfmt *usf; + struct unisig *usp; + KBuffer *buf; + int op; + int headroom; +{ + KBuffer *m; + + ATM_DEBUG3("usf_init: usf=0x%x, buf=0x%x, op=%d\n", + (int) usf, (int) buf, op); + + /* + * Check parameters + */ + if (!usf) + return(EINVAL); + + switch(op) { + + case USF_ENCODE: + /* + * Get a buffer + */ + KB_ALLOCPKT(m, USF_MIN_ALLOC, KB_F_NOWAIT, KB_T_DATA); + if (m == NULL) + return(ENOMEM); + KB_LEN(m) = 0; + if (headroom < KB_BFRLEN(m)) { + KB_HEADSET(m, headroom); + } + break; + + case USF_DECODE: + /* + * Verify buffer address + */ + if (!buf) + return(EINVAL); + m = buf; + break; + + default: + return(EINVAL); + } + + /* + * Save parameters in formatting structure + */ + usf->usf_m_addr = m; + usf->usf_m_base = m; + usf->usf_loc = 0; + usf->usf_op = op; + usf->usf_sig = usp; + + return(0); +} + + +/* + * Get or put the next byte of a signalling message + * + * Arguments: + * usf pointer to a unisig formatting structure + * c pointer to the byte to send from or receive into + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +usf_byte(usf, c) + struct usfmt *usf; + u_char *c; +{ + u_char *mp; + KBuffer *m = usf->usf_m_addr, *m1; + int space; + + switch (usf->usf_op) { + + case USF_DECODE: + /* + * Make sure we're not past the end of the buffer + * (allowing for zero-length buffers) + */ + while (usf->usf_loc >= KB_LEN(m)) { + if (KB_NEXT(usf->usf_m_addr)) { + usf->usf_m_addr = m = KB_NEXT(usf->usf_m_addr); + usf->usf_loc = 0; + } else { + return(EMSGSIZE); + } + } + + /* + * Get the data from the buffer + */ + KB_DATASTART(m, mp, u_char *); + *c = mp[usf->usf_loc]; + usf->usf_loc++; + break; + + case USF_ENCODE: + /* + * If the current buffer is full, get another + */ + KB_TAILROOM(m, space); + if (space == 0) { + KB_ALLOC(m1, USF_MIN_ALLOC, KB_F_NOWAIT, KB_T_DATA); + if (m1 == NULL) + return(ENOMEM); + KB_LEN(m1) = 0; + KB_LINK(m1, m); + usf->usf_m_addr = m = m1; + usf->usf_loc = 0; + } + + /* + * Put the data into the buffer + */ + KB_DATASTART(m, mp, u_char *); + mp[usf->usf_loc] = *c; + KB_TAILADJ(m, 1); + usf->usf_loc++; + break; + + default: + /* + * Invalid operation code + */ + return(EINVAL); + } + + return(0); + +} + +/* + * Get or put a short integer + * + * Arguments: + * usf pointer to a unisig formatting structure + * s pointer to a short to send from or receive into + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +usf_short(usf, s) + struct usfmt *usf; + u_short *s; + +{ + int rc; + union { + u_short value; + u_char b[sizeof(u_short)]; + } tval; + + tval.value = 0; + if (usf->usf_op == USF_ENCODE) + tval.value = htons(*s); + + if (rc = usf_byte(usf, &tval.b[0])) + return(rc); + if (rc = usf_byte(usf, &tval.b[1])) + return(rc); + + if (usf->usf_op == USF_DECODE) + *s = ntohs(tval.value); + + return(0); +} + + +/* + * Get or put a 3-byte integer + * + * Arguments: + * usf pointer to a unisig formatting structure + * i pointer to an integer to send from or receive into + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +usf_int3(usf, i) + struct usfmt *usf; + u_int *i; + +{ + int j, rc; + union { + u_int value; + u_char b[sizeof(u_int)]; + } tval; + + tval.value = 0; + + if (usf->usf_op == USF_ENCODE) + tval.value = htonl(*i); + + for (j=0; j<3; j++) { + rc = usf_byte(usf, &tval.b[j+sizeof(u_int)-3]); + if (rc) + return(rc); + } + + if (usf->usf_op == USF_DECODE) + *i = ntohl(tval.value); + + return(rc); +} + + +/* + * Get or put an integer + * + * Arguments: + * usf pointer to a unisig formatting structure + * i pointer to an integer to send from or receive into + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +usf_int(usf, i) + struct usfmt *usf; + u_int *i; + +{ + int j, rc; + union { + u_int value; + u_char b[sizeof(u_int)]; + } tval; + + if (usf->usf_op == USF_ENCODE) + tval.value = htonl(*i); + + for (j=0; j<4; j++) { + rc = usf_byte(usf, &tval.b[j+sizeof(u_int)-4]); + if (rc) + return(rc); + } + + if (usf->usf_op == USF_DECODE) + *i = ntohl(tval.value); + + return(rc); +} + + +/* + * Get or put an extented field + * + * An extented field consists of a string of bytes. All but the last + * byte of the field has the high-order bit set to zero. When decoding, + * this routine will read bytes until either the input is exhausted or + * a byte with a high-order one is found. Whe encoding, it will take an + * unsigned integer and write until the highest-order one bit has been + * written. + * + * Arguments: + * usf pointer to a unisig formatting structure + * i pointer to an integer to send from or receive into + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +usf_ext(usf, i) + struct usfmt *usf; + u_int *i; + +{ + int j, rc; + u_char c, buff[sizeof(u_int)+1]; + u_int val; + union { + u_int value; + u_char b[sizeof(u_int)]; + } tval; + + switch(usf->usf_op) { + + case USF_ENCODE: + val = *i; + j = 0; + while (val) { + tval.value = htonl(val); + buff[j] = tval.b[sizeof(u_int)-1] & UNI_IE_EXT_MASK; + val >>= 7; + j++; + } + j--; + buff[0] |= UNI_IE_EXT_BIT; + for (; j>=0; j--) { + rc = usf_byte(usf, &buff[j]); + if (rc) + return(rc); + } + break; + + case USF_DECODE: + c = 0; + val = 0; + while (!(c & UNI_IE_EXT_BIT)) { + rc = usf_byte(usf, &c); + if (rc) + return(rc); + val = (val << 7) + (c & UNI_IE_EXT_MASK); + } + *i = val; + break; + + default: + return(EINVAL); + } + + return(0); +} + + +/* + * Count the bytes remaining to be decoded + * + * Arguments: + * usf pointer to a unisig formatting structure + * + * Returns: + * int the number of bytes in the buffer chain remaining to + * be decoded + * + */ +int +usf_count(usf) + struct usfmt *usf; +{ + int count; + KBuffer *m = usf->usf_m_addr; + + /* + * Return zero if we're not decoding + */ + if (usf->usf_op != USF_DECODE) + return (0); + + /* + * Calculate the length of data remaining in the current buffer + */ + count = KB_LEN(m) - usf->usf_loc; + + /* + * Loop through any remaining buffers, adding in their lengths + */ + while (KB_NEXT(m)) { + m = KB_NEXT(m); + count += KB_LEN(m); + } + + return(count); + +} + + +/* + * Get or put the next byte of a signalling message and return + * the byte's buffer address + * + * Arguments: + * usf pointer to a unisig formatting structure + * c pointer to the byte to send from or receive into + * bp address to store the byte's buffer address + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +usf_byte_mark(usf, c, bp) + struct usfmt *usf; + u_char *c; + u_char **bp; +{ + u_char *mp; + int rc; + + /* + * First, get/put the data byte + */ + rc = usf_byte(usf, c); + if (rc) { + + /* + * Error encountered + */ + *bp = NULL; + return (rc); + } + + /* + * Now return the buffer address of that byte + */ + KB_DATASTART(usf->usf_m_addr, mp, u_char *); + *bp = &mp[usf->usf_loc - 1]; + + return (0); +} + diff --git a/sys/netatm/uni/unisig_mbuf.h b/sys/netatm/uni/unisig_mbuf.h new file mode 100644 index 0000000..f394047 --- /dev/null +++ b/sys/netatm/uni/unisig_mbuf.h @@ -0,0 +1,58 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: unisig_mbuf.h,v 1.5 1998/08/26 23:29:22 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Message buffer formats + * + */ + +#ifndef _UNI_SIG_MBUF_H +#define _UNI_SIG_MBUF_H + + +/* + * Structure for message encoding/decoding information. + */ +struct usfmt { + KBuffer *usf_m_addr; /* Current buffer */ + KBuffer *usf_m_base; /* First buffer in chain */ + int usf_loc; /* Offset in current buffer */ + int usf_op; /* Operation (see below) */ + struct unisig *usf_sig; /* UNI signalling instance */ +}; + +#define USF_ENCODE 1 +#define USF_DECODE 2 + +#define USF_MIN_ALLOC MHLEN /* Minimum encoding buffer size */ + +#endif /* _UNI_SIG_MBUF_H */ diff --git a/sys/netatm/uni/unisig_msg.c b/sys/netatm/uni/unisig_msg.c new file mode 100644 index 0000000..22bf469 --- /dev/null +++ b/sys/netatm/uni/unisig_msg.c @@ -0,0 +1,1002 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: unisig_msg.c,v 1.10 1998/08/26 23:29:22 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Message handling module + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_msg.c,v 1.10 1998/08/26 23:29:22 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/unisig.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/unisig_msg.h> +#include <netatm/uni/unisig_mbuf.h> +#include <netatm/uni/unisig_print.h> + + +/* + * Local functions + */ +static void unisig_rcv_restart __P((struct unisig *, struct unisig_msg *)); +static void unisig_rcv_setup __P((struct unisig *, struct unisig_msg *)); + + +/* + * Local variables + */ +#ifdef DIAGNOSTIC +static int unisig_print_msg = 0; +#endif + + +/* + * Set a Cause IE based on information in an ATM attribute block + * + * Arguments: + * iep pointer to a cause IE + * msg pointer to message + * cause cause code for the error + * + * Returns: + * 0 message sent OK + * errno error encountered + * + */ +void +unisig_cause_from_attr(iep, aap) + struct ie_generic *iep; + Atm_attributes *aap; +{ + /* + * Copy cause info from attribute block to IE + */ + iep->ie_ident = UNI_IE_CAUS; + iep->ie_coding = aap->cause.v.coding_standard; + iep->ie_caus_loc = aap->cause.v.location; + iep->ie_caus_cause = aap->cause.v.cause_value; +} + + +/* + * Set a Cause IE based on information in a UNI signalling message + * + * Arguments: + * iep pointer to a cause IE + * msg pointer to message + * cause cause code for the error + * + * Returns: + * 0 message sent OK + * errno error encountered + * + */ +void +unisig_cause_from_msg(iep, msg, cause) + struct ie_generic *iep; + struct unisig_msg *msg; + int cause; +{ + struct ie_generic *ie1; + int i; + + /* + * Fill out the cause IE fixed fields + */ + iep->ie_ident = UNI_IE_CAUS; + iep->ie_caus_loc = UNI_IE_CAUS_LOC_USER; + iep->ie_caus_cause = cause; + + /* + * Set diagnostics if indicated + */ + switch(cause) { + case UNI_IE_CAUS_IECONTENT: + iep->ie_caus_diag_len = 0; + for (i = 0, ie1 = msg->msg_ie_err; + ie1 && i < UNI_IE_CAUS_MAX_ID; + ie1 = ie1->ie_next) { + if (ie1->ie_err_cause == UNI_IE_CAUS_IECONTENT) { + iep->ie_caus_diagnostic[i] = + ie1->ie_ident; + iep->ie_caus_diag_len++; + i++; + } + } + break; + case UNI_IE_CAUS_REJECT: + iep->ie_caus_diag_len = 2; + iep->ie_caus_diagnostic[0] = UNI_IE_EXT_BIT + + (UNI_IE_CAUS_RR_USER << UNI_IE_CAUS_RR_SHIFT) + + UNI_IE_CAUS_RC_TRANS; + iep->ie_caus_diagnostic[1] = 0; + break; + case UNI_IE_CAUS_MISSING: + iep->ie_caus_diag_len = 0; + for (i = 0, ie1 = msg->msg_ie_err; + ie1 && i < UNI_IE_CAUS_MAX_ID; + ie1 = ie1->ie_next) { + if (ie1->ie_err_cause == UNI_IE_CAUS_MISSING) { + iep->ie_caus_diagnostic[i] = + ie1->ie_ident; + iep->ie_caus_diag_len++; + i++; + } + } + } +} + + +/* + * Send a UNISIG signalling message + * + * Called to send a Q.2931 message. This routine encodes the message + * and hands it to SSCF for transmission. + * + * Arguments: + * usp pointer to UNISIG protocol instance block + * msg pointer to message + * + * Returns: + * 0 message sent OK + * errno error encountered + * + */ +int +unisig_send_msg(usp, msg) + struct unisig *usp; + struct unisig_msg *msg; +{ + int err = 0; + struct usfmt usf; + + ATM_DEBUG2("unisig_send_msg: msg=0x%x, type=%d\n", msg, + msg->msg_type); + + /* + * Make sure the network is up + */ + if (usp->us_state != UNISIG_ACTIVE) + return(ENETDOWN); + +#ifdef DIAGNOSTIC + /* + * Print the message we're sending. + */ + if (unisig_print_msg) + usp_print_msg(msg, UNISIG_MSG_OUT); +#endif + + /* + * Convert message to network order + */ + err = usf_init(&usf, usp, (KBuffer *) 0, USF_ENCODE, + usp->us_headout); + if (err) + return(err); + + err = usf_enc_msg(&usf, msg); + if (err) { + ATM_DEBUG1("unisig_send_msg: encode failed with %d\n", + err); + KB_FREEALL(usf.usf_m_base); + return(EIO); + } + +#ifdef DIAGNOSTIC + /* + * Print the converted message + */ + if (unisig_print_msg > 1) + unisig_print_mbuf(usf.usf_m_base); +#endif + + /* + * Send the message + */ + err = atm_cm_saal_data(usp->us_conn, usf.usf_m_base); + if (err) + KB_FREEALL(usf.usf_m_base); + + return(err); +} + + +/* + * Send a SETUP request + * + * Build and send a Q.2931 SETUP message. + * + * Arguments: + * usp pointer to UNISIG protocol instance block + * uvp pointer to VCCB for which the request is being sent + * + * Returns: + * none + * + */ +int +unisig_send_setup(usp, uvp) + struct unisig *usp; + struct unisig_vccb *uvp; +{ + int err = 0; + struct unisig_msg *setup; + Atm_attributes *ap = &uvp->uv_connvc->cvc_attr; + + ATM_DEBUG1("unisig_send_setup: uvp=0x%x\n", (int) uvp); + + /* + * Make sure required connection attriutes are set + */ + if (ap->aal.tag != T_ATM_PRESENT || + ap->traffic.tag != T_ATM_PRESENT || + ap->bearer.tag != T_ATM_PRESENT || + ap->called.tag != T_ATM_PRESENT || + ap->qos.tag != T_ATM_PRESENT) { + err = EINVAL; + setup = NULL; + goto done; + } + + /* + * Get memory for a SETUP message + */ + setup = (struct unisig_msg *)atm_allocate(&unisig_msgpool); + if (setup == NULL) { + err = ENOMEM; + goto done; + } + + /* + * Fill in the SETUP message + */ + if (!uvp->uv_call_ref) + uvp->uv_call_ref = unisig_alloc_call_ref(usp); + setup->msg_call_ref = uvp->uv_call_ref; + setup->msg_type = UNI_MSG_SETU; + + /* + * Set IEs from connection attributes + */ + err = unisig_set_attrs(usp, setup, ap); + if (err) + goto done; + + /* + * Attach a Calling Party Number IE if the user didn't + * specify one in the attribute block + */ + if (ap->calling.tag != T_ATM_PRESENT) { + setup->msg_ie_cgad = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (setup->msg_ie_cgad == NULL) { + err = ENOMEM; + goto done; + } + setup->msg_ie_cgad->ie_ident = UNI_IE_CGAD; + ATM_ADDR_COPY(&usp->us_addr, + &setup->msg_ie_cgad->ie_cgad_addr); + ATM_ADDR_SEL_COPY(&usp->us_addr, + uvp->uv_nif ? uvp->uv_nif->nif_sel : 0, + &setup->msg_ie_cgad->ie_cgad_addr); + } + + /* + * Send the SETUP message + */ + err = unisig_send_msg(usp, setup); + +done: + if (setup) + unisig_free_msg(setup); + + return(err); +} + + +/* + * Send a RELEASE message + * + * Arguments: + * usp pointer to UNISIG protocol instance block + * uvp pointer to VCCB for which the RELEASE is being sent + * msg pointer to UNI signalling message that the RELEASE + * responds to (may be NULL) + * cause the reason for the RELEASE; a value of + * T_ATM_ABSENT indicates that the cause code is + * in the VCC's ATM attributes block + * + * Returns: + * none + * + */ +int +unisig_send_release(usp, uvp, msg, cause) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; + int cause; +{ + int err = 0; + struct unisig_msg *rls_msg; + struct ie_generic *cause_ie; + + ATM_DEBUG2("unisig_send_release: usp=0x%x, uvp=0x%x\n", + (int) usp, (int) uvp); + + /* + * Get memory for a RELEASE message + */ + rls_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool); + if (rls_msg == NULL) { + return(ENOMEM); + } + cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool); + if (cause_ie == NULL) { + atm_free(rls_msg); + return(ENOMEM); + } + + /* + * Fill in the RELEASE message + */ + rls_msg->msg_call_ref = uvp->uv_call_ref; + rls_msg->msg_type = UNI_MSG_RLSE; + rls_msg->msg_type_flag = 0; + rls_msg->msg_type_action = 0; + rls_msg->msg_ie_caus = cause_ie; + + /* + * Fill out the cause IE + */ + cause_ie->ie_ident = UNI_IE_CAUS; + if (cause == T_ATM_ABSENT) { + unisig_cause_from_attr(cause_ie, + &uvp->uv_connvc->cvc_attr); + } else { + cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER; + unisig_cause_from_msg(cause_ie, msg, cause); + } + + /* + * Send the RELEASE + */ + err = unisig_send_msg(usp, rls_msg); + unisig_free_msg(rls_msg); + + return(err); +} + + +/* + * Send a RELEASE COMPLETE message + * + * Arguments: + * usp pointer to UNISIG protocol instance block + * uvp pointer to VCCB for which the RELEASE is being sent. + * NULL indicates that a VCCB wasn't found for a call + * reference value. + * msg pointer to the message which triggered the send + * cause the cause code for the message; a value of + * T_ATM_ABSENT indicates that the cause code is + * in the VCC's ATM attributes block + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +unisig_send_release_complete(usp, uvp, msg, cause) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; + int cause; +{ + int err = 0; + struct unisig_msg *rls_cmp; + struct ie_generic *cause_ie; + + ATM_DEBUG4("unisig_send_release_complete usp=0x%x, uvp=0x%x, msg=0x%x, cause=%d\n", + (int) usp, (int) uvp, (int) msg, cause); + + /* + * Get memory for a RELEASE COMPLETE message + */ + rls_cmp = (struct unisig_msg *) atm_allocate(&unisig_msgpool); + if (rls_cmp == NULL) { + return(ENOMEM); + } + cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool); + if (cause_ie == NULL) { + atm_free(rls_cmp); + return(ENOMEM); + } + + /* + * Fill in the RELEASE COMPLETE message + */ + if (uvp) { + rls_cmp->msg_call_ref = uvp->uv_call_ref; + } else if (msg) { + rls_cmp->msg_call_ref = EXTRACT_CREF(msg->msg_call_ref); + } else { + rls_cmp->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL; + } + rls_cmp->msg_type = UNI_MSG_RLSC; + rls_cmp->msg_type_flag = 0; + rls_cmp->msg_type_action = 0; + rls_cmp->msg_ie_caus = cause_ie; + + /* + * Fill out the cause IE + */ + cause_ie->ie_ident = UNI_IE_CAUS; + if (cause == T_ATM_ABSENT) { + unisig_cause_from_attr(cause_ie, + &uvp->uv_connvc->cvc_attr); + } else { + cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER; + unisig_cause_from_msg(cause_ie, msg, cause); + } + + /* + * Send the RELEASE COMPLETE + */ + err = unisig_send_msg(usp, rls_cmp); + unisig_free_msg(rls_cmp); + + return(err); +} + + +/* + * Send a STATUS message + * + * Arguments: + * usp pointer to UNISIG protocol instance block + * uvp pointer to VCCB for which the STATUS is being sent. + * NULL indicates that a VCCB wasn't found for a call + * reference value. + * msg pointer to the message which triggered the send + * cause the cause code to include in the message + * + * Returns: + * none + * + */ +int +unisig_send_status(usp, uvp, msg, cause) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; + int cause; +{ + int err = 0, i; + struct unisig_msg *stat_msg; + struct ie_generic *cause_ie, *clst_ie, *iep; + + ATM_DEBUG4("unisig_send_status: usp=0x%x, uvp=0x%x, msg=0x%x, cause=%d\n", + (int) usp, (int) uvp, (int) msg, cause); + + /* + * Get memory for a STATUS message + */ + stat_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool); + if (stat_msg == NULL) { + return(ENOMEM); + } + cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool); + if (cause_ie == NULL) { + atm_free(stat_msg); + return(ENOMEM); + } + clst_ie = (struct ie_generic *) atm_allocate(&unisig_iepool); + if (clst_ie == NULL) { + atm_free(stat_msg); + atm_free(cause_ie); + return(ENOMEM); + } + + /* + * Fill in the STATUS message + */ + if (uvp) { + stat_msg->msg_call_ref = uvp->uv_call_ref; + } else if (msg) { + stat_msg->msg_call_ref = + EXTRACT_CREF(msg->msg_call_ref); + } else { + stat_msg->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL; + } + stat_msg->msg_type = UNI_MSG_STAT; + stat_msg->msg_type_flag = 0; + stat_msg->msg_type_action = 0; + stat_msg->msg_ie_clst = clst_ie; + stat_msg->msg_ie_caus = cause_ie; + + /* + * Fill out the call state IE + */ + clst_ie->ie_ident = UNI_IE_CLST; + clst_ie->ie_coding = 0; + clst_ie->ie_flag = 0; + clst_ie->ie_action = 0; + if (uvp) { + clst_ie->ie_clst_state = uvp->uv_sstate; + } else { + clst_ie->ie_clst_state = UNI_NULL; + } + + /* + * Fill out the cause IE + */ + cause_ie->ie_ident = UNI_IE_CAUS; + cause_ie->ie_coding = 0; + cause_ie->ie_flag = 0; + cause_ie->ie_action = 0; + cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER; + cause_ie->ie_caus_cause = cause; + switch (cause) { + case UNI_IE_CAUS_MTEXIST: + case UNI_IE_CAUS_STATE: + if (msg) { + cause_ie->ie_caus_diagnostic[0] = msg->msg_type; + } + break; + case UNI_IE_CAUS_MISSING: + case UNI_IE_CAUS_IECONTENT: + case UNI_IE_CAUS_IEEXIST: + for (i=0, iep=msg->msg_ie_err; + iep && i<UNI_MSG_IE_CNT; + i++, iep = iep->ie_next) { + if (iep->ie_err_cause == cause) { + cause_ie->ie_caus_diagnostic[i] = + iep->ie_ident; + } + } + } + + /* + * Send the STATUS message + */ + err = unisig_send_msg(usp, stat_msg); + unisig_free_msg(stat_msg); + + return(err); +} + + +/* + * Process a RESTART message + * + * Arguments: + * usp pointer to UNISIG protocol instance block + * msg pointer to the RESTART message + * + * Returns: + * none + * + */ +static void +unisig_rcv_restart(usp, msg) + struct unisig *usp; + struct unisig_msg *msg; +{ + struct unisig_vccb *uvp, *uvnext; + struct unisig_msg *rsta_msg; + int s; + + ATM_DEBUG2("unisig_rcv_restart: usp=0x%x, msg=0x%x\n", + usp, msg); + + /* + * Check what class of VCCs we're supposed to restart + */ + if (msg->msg_ie_rsti->ie_rsti_class == UNI_IE_RSTI_IND_VC) { + /* + * Just restart the indicated VCC + */ + if (msg->msg_ie_cnid) { + uvp = unisig_find_vpvc(usp, + msg->msg_ie_cnid->ie_cnid_vpci, + msg->msg_ie_cnid->ie_cnid_vci, + 0); + if (uvp && uvp->uv_type & VCC_SVC) { + (void) unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + } + } + } else { + /* + * Restart all VCCs + */ + s = splnet(); + for (uvp=Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp; + uvp=uvnext) { + uvnext = Q_NEXT(uvp, struct unisig_vccb, + uv_sigelem); + if (uvp->uv_type & VCC_SVC) { + (void) unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + } + } + (void) splx(s); + } + + /* + * Get memory for a RESTART ACKNOWLEDGE message + */ + rsta_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool); + if (rsta_msg == NULL) { + return; + } + + /* + * Fill out the message + */ + rsta_msg->msg_call_ref = EXTRACT_CREF(msg->msg_call_ref); + rsta_msg->msg_type = UNI_MSG_RSTA; + rsta_msg->msg_type_flag = 0; + rsta_msg->msg_type_action = 0; + rsta_msg->msg_ie_rsti = msg->msg_ie_rsti; + if (msg->msg_ie_cnid) { + rsta_msg->msg_ie_cnid = msg->msg_ie_cnid; + } + + /* + * Send the message + */ + (void) unisig_send_msg(usp, rsta_msg); + rsta_msg->msg_ie_rsti = NULL; + rsta_msg->msg_ie_cnid = NULL; + unisig_free_msg(rsta_msg); + + return; +} + + +/* + * Process a SETUP message + * + * Arguments: + * usp pointer to UNISIG protocol instance block + * msg pointer to the SETUP message + * + * Returns: + * none + * + */ +static void +unisig_rcv_setup(usp, msg) + struct unisig *usp; + struct unisig_msg *msg; +{ + struct unisig_vccb *uvp = NULL; + struct ie_generic *iep; + + ATM_DEBUG2("unisig_rcv_setup: usp=0x%x, msg=0x%x\n", usp, msg); + + /* + * If we already have a VCC with the call reference, + * ignore the SETUP message + */ + uvp = unisig_find_conn(usp, EXTRACT_CREF(msg->msg_call_ref)); + if (uvp) + return; + + /* + * If the call reference flag is incorrectly set, + * ignore the SETUP message + */ + if (msg->msg_call_ref & UNI_MSG_CALL_REF_RMT) + return; + + /* + * If there are missing mandatory IEs, send a + * RELEASE COMPLETE message and ignore the SETUP + */ + for (iep = msg->msg_ie_err; iep; iep = iep->ie_next) { + if (iep->ie_err_cause == UNI_IE_CAUS_MISSING) { + (void) unisig_send_release_complete(usp, + uvp, msg, UNI_IE_CAUS_MISSING); + return; + } + } + + /* + * If there are mandatory IEs with invalid content, send a + * RELEASE COMPLETE message and ignore the SETUP + */ + for (iep = msg->msg_ie_err; iep; iep = iep->ie_next) { + if (iep->ie_err_cause == UNI_IE_CAUS_IECONTENT) { + (void) unisig_send_release_complete(usp, + uvp, msg, + UNI_IE_CAUS_IECONTENT); + return; + } + } + + /* + * Get a new VCCB for the connection + */ + uvp = (struct unisig_vccb *)atm_allocate(&unisig_vcpool); + if (uvp == NULL) { + return; + } + + /* + * Put the VCCB on the UNISIG queue + */ + ENQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq); + + /* + * Set the state and call reference value + */ + uvp->uv_sstate = UNI_NULL; + uvp->uv_call_ref = EXTRACT_CREF(msg->msg_call_ref); + + /* + * Pass the VCCB and message to the VC state machine + */ + (void) unisig_vc_state(usp, uvp, UNI_VC_SETUP_MSG, msg); + + /* + * If the VCCB state is NULL, the open failed and the + * VCCB should be released + */ + if (uvp->uv_sstate == UNI_NULL) { + DEQUEUE(uvp, struct unisig_vccb, uv_sigelem, + usp->us_vccq); + atm_free(uvp); + } + + return; +} + + +/* + * Process a UNISIG signalling message + * + * Called when a UNISIG message is received. The message is decoded + * and passed to the UNISIG state machine. Unrecognized and + * unexpected messages are logged. + * + * Arguments: + * usp pointer to UNISIG protocol instance block + * m pointer to a buffer chain containing the UNISIG message + * + * Returns: + * none + * + */ +int +unisig_rcv_msg(usp, m) + struct unisig *usp; + KBuffer *m; +{ + int err; + u_int cref; + struct usfmt usf; + struct unisig_msg *msg = 0; + struct unisig_vccb *uvp = 0; + struct ie_generic *iep; + + ATM_DEBUG2("unisig_rcv_msg: bfr=0x%x, len=%d\n", (int)m, KB_LEN(m)); + +#ifdef NOTDEF + unisig_print_mbuf(m); +#endif + + /* + * Get storage for the message + */ + msg = (struct unisig_msg *)atm_allocate(&unisig_msgpool); + if (msg == NULL) { + err = ENOMEM; + goto done; + } + + /* + * Convert the message from network order to internal format + */ + err = usf_init(&usf, usp, m, USF_DECODE, 0); + if (err) { + if (err == EINVAL) + panic("unisig_rcv_msg: invalid parameter\n"); + ATM_DEBUG1("unisig_rcv_msg: decode init failed with %d\n", + err); + goto done; + } + + err = usf_dec_msg(&usf, msg); + if (err) { + ATM_DEBUG1("unisig_rcv_msg: decode failed with %d\n", + err); + goto done; + } + +#ifdef DIAGNOSTIC + /* + * Debug--print some information about the message + */ + if (unisig_print_msg) + usp_print_msg(msg, UNISIG_MSG_IN); +#endif + + /* + * Get the call reference value + */ + cref = EXTRACT_CREF(msg->msg_call_ref); + + /* + * Any message with the global call reference value except + * RESTART, RESTART ACK, or STATUS is in error + */ + if (GLOBAL_CREF(cref) && + msg->msg_type != UNI_MSG_RSTR && + msg->msg_type != UNI_MSG_RSTA && + msg->msg_type != UNI_MSG_STAT) { + /* + * Send STATUS message indicating the error + */ + err = unisig_send_status(usp, (struct unisig_vccb *) 0, + msg, UNI_IE_CAUS_CREF); + goto done; + } + + /* + * Check for missing mandatory IEs. Checks for SETUP, + * RELEASE, and RELEASE COMPLETE are handled elsewhere. + */ + if (msg->msg_type != UNI_MSG_SETU && + msg->msg_type != UNI_MSG_RLSE && + msg->msg_type != UNI_MSG_RLSC) { + for (iep = msg->msg_ie_err; iep; iep = iep->ie_next) { + if (iep->ie_err_cause == UNI_IE_CAUS_MISSING) { + err = unisig_send_status(usp, + uvp, msg, + UNI_IE_CAUS_MISSING); + goto done; + } + } + } + + /* + * Find the VCCB associated with the message + */ + uvp = unisig_find_conn(usp, cref); + + /* + * Process the message based on its type + */ + switch(msg->msg_type) { + case UNI_MSG_CALP: + (void) unisig_vc_state(usp, uvp, + UNI_VC_CALLP_MSG, msg); + break; + case UNI_MSG_CONN: + (void) unisig_vc_state(usp, uvp, + UNI_VC_CONNECT_MSG, msg); + break; + case UNI_MSG_CACK: + (void) unisig_vc_state(usp, uvp, + UNI_VC_CNCTACK_MSG, msg); + break; + case UNI_MSG_SETU: + unisig_rcv_setup(usp, msg); + break; + case UNI_MSG_RLSE: + (void) unisig_vc_state(usp, uvp, + UNI_VC_RELEASE_MSG, msg); + break; + case UNI_MSG_RLSC: + /* + * Ignore a RELEASE COMPLETE with an unrecognized + * call reference value + */ + if (uvp) { + (void) unisig_vc_state(usp, uvp, + UNI_VC_RLSCMP_MSG, msg); + } + break; + case UNI_MSG_RSTR: + unisig_rcv_restart(usp, msg); + break; + case UNI_MSG_RSTA: + break; + case UNI_MSG_STAT: + (void) unisig_vc_state(usp, uvp, + UNI_VC_STATUS_MSG, msg); + break; + case UNI_MSG_SENQ: + (void) unisig_vc_state(usp, uvp, + UNI_VC_STATUSENQ_MSG, msg); + break; + case UNI_MSG_ADDP: + (void) unisig_vc_state(usp, uvp, + UNI_VC_ADDP_MSG, msg); + break; + case UNI_MSG_ADPA: + (void) unisig_vc_state(usp, uvp, + UNI_VC_ADDPACK_MSG, msg); + break; + case UNI_MSG_ADPR: + (void) unisig_vc_state(usp, uvp, + UNI_VC_ADDPREJ_MSG, msg); + break; + case UNI_MSG_DRPP: + (void) unisig_vc_state(usp, uvp, + UNI_VC_DROP_MSG, msg); + break; + case UNI_MSG_DRPA: + (void) unisig_vc_state(usp, uvp, + UNI_VC_DROPACK_MSG, msg); + break; + default: + /* + * Message size didn't match size received + */ + err = unisig_send_status(usp, uvp, msg, + UNI_IE_CAUS_MTEXIST); + } + +done: + /* + * Handle message errors that require a response + */ + switch(err) { + case EMSGSIZE: + /* + * Message size didn't match size received + */ + err = unisig_send_status(usp, uvp, msg, + UNI_IE_CAUS_LEN); + break; + } + + /* + * Free the incoming message (both buffer and internal format) + * if necessary. + */ + if (msg) + unisig_free_msg(msg); + if (m) + KB_FREEALL(m); + + return (err); +} diff --git a/sys/netatm/uni/unisig_msg.h b/sys/netatm/uni/unisig_msg.h new file mode 100644 index 0000000..4be0144 --- /dev/null +++ b/sys/netatm/uni/unisig_msg.h @@ -0,0 +1,953 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: unisig_msg.h,v 1.8 1998/08/26 23:29:23 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Message formatting blocks + * + */ + +#ifndef _UNI_SIG_MSG_H +#define _UNI_SIG_MSG_H + +#define UNI_MSG_DISC_Q93B 0x09 +#define UNI_MSG_MIN_LEN 9 + +/* + * Values for Q.2931 message type. + */ +#define UNI_MSG_CALP 0x02 +#define UNI_MSG_CONN 0x07 +#define UNI_MSG_CACK 0x0F +#define UNI_MSG_SETU 0x05 +#define UNI_MSG_RLSE 0x4D +#define UNI_MSG_RLSC 0x5A +#define UNI_MSG_RSTR 0x46 +#define UNI_MSG_RSTA 0x4E +#define UNI_MSG_STAT 0x7D +#define UNI_MSG_SENQ 0x75 +#define UNI_MSG_ADDP 0x80 +#define UNI_MSG_ADPA 0x81 +#define UNI_MSG_ADPR 0x82 +#define UNI_MSG_DRPP 0x83 +#define UNI_MSG_DRPA 0x84 + + +/* + * Values for information element identifier. + */ +#define UNI_IE_CAUS 0x08 +#define UNI_IE_CLST 0x14 +#define UNI_IE_EPRF 0x54 +#define UNI_IE_EPST 0x55 +#define UNI_IE_AALP 0x58 +#define UNI_IE_CLRT 0x59 +#define UNI_IE_CNID 0x5A +#define UNI_IE_QOSP 0x5C +#define UNI_IE_BHLI 0x5D +#define UNI_IE_BBCP 0x5E +#define UNI_IE_BLLI 0x5F +#define UNI_IE_BLSH 0x60 +#define UNI_IE_BNSH 0x61 +#define UNI_IE_BSDC 0x62 +#define UNI_IE_BRPI 0x63 +#define UNI_IE_CGAD 0x6C +#define UNI_IE_CGSA 0x6D +#define UNI_IE_CDAD 0x70 +#define UNI_IE_CDSA 0x71 +#define UNI_IE_TRNT 0x78 +#define UNI_IE_RSTI 0x79 + +/* + * Masks for information element extension in bit 8 + */ +#define UNI_IE_EXT_BIT 0x80 +#define UNI_IE_EXT_MASK 0x7F + + +/* + * Signalling message in internal format. + */ +#define UNI_MSG_IE_CNT 22 + +struct unisig_msg { + u_int msg_call_ref; + u_char msg_type; + u_char msg_type_flag; + u_char msg_type_action; + int msg_length; + struct ie_generic *msg_ie_vec[UNI_MSG_IE_CNT]; +}; + +#define UNI_MSG_CALL_REF_RMT 0x800000 +#define UNI_MSG_CALL_REF_MASK 0x7FFFFF +#define UNI_MSG_CALL_REF_GLOBAL 0 +#define UNI_MSG_CALL_REF_DUMMY 0x7FFFFF + +#define EXTRACT_CREF(x) \ + ((x) & UNI_MSG_CALL_REF_RMT ? (x) & UNI_MSG_CALL_REF_MASK : (x) | UNI_MSG_CALL_REF_RMT) +#define GLOBAL_CREF(x) ((x) & UNI_MSG_CALL_REF_MASK == UNI_MSG_CALL_REF_GLOBAL) +#define DUMMY_CREF(x) ((x) & UNI_MSG_CALL_REF_MASK == UNI_MSG_CALL_REF_DUMMY) + +#define UNI_MSG_TYPE_FLAG_MASK 1 +#define UNI_MSG_TYPE_FLAG_SHIFT 4 + +#define UNI_MSG_TYPE_ACT_CLEAR 0 +#define UNI_MSG_TYPE_ACT_DISC 1 +#define UNI_MSG_TYPE_ACT_RPRT 2 +#define UNI_MSG_TYPE_ACT_RSVD 3 +#define UNI_MSG_TYPE_ACT_MASK 3 + +#define UNI_MSG_IE_AALP 0 +#define UNI_MSG_IE_CLRT 1 +#define UNI_MSG_IE_BBCP 2 +#define UNI_MSG_IE_BHLI 3 +#define UNI_MSG_IE_BLLI 4 +#define UNI_MSG_IE_CLST 5 +#define UNI_MSG_IE_CDAD 6 +#define UNI_MSG_IE_CDSA 7 +#define UNI_MSG_IE_CGAD 8 +#define UNI_MSG_IE_CGSA 9 +#define UNI_MSG_IE_CAUS 10 +#define UNI_MSG_IE_CNID 11 +#define UNI_MSG_IE_QOSP 12 +#define UNI_MSG_IE_BRPI 13 +#define UNI_MSG_IE_RSTI 14 +#define UNI_MSG_IE_BLSH 15 +#define UNI_MSG_IE_BNSH 16 +#define UNI_MSG_IE_BSDC 17 +#define UNI_MSG_IE_TRNT 18 +#define UNI_MSG_IE_EPRF 19 +#define UNI_MSG_IE_EPST 20 +#define UNI_MSG_IE_ERR 21 + +#define msg_ie_aalp msg_ie_vec[UNI_MSG_IE_AALP] +#define msg_ie_clrt msg_ie_vec[UNI_MSG_IE_CLRT] +#define msg_ie_bbcp msg_ie_vec[UNI_MSG_IE_BBCP] +#define msg_ie_bhli msg_ie_vec[UNI_MSG_IE_BHLI] +#define msg_ie_blli msg_ie_vec[UNI_MSG_IE_BLLI] +#define msg_ie_clst msg_ie_vec[UNI_MSG_IE_CLST] +#define msg_ie_cdad msg_ie_vec[UNI_MSG_IE_CDAD] +#define msg_ie_cdsa msg_ie_vec[UNI_MSG_IE_CDSA] +#define msg_ie_cgad msg_ie_vec[UNI_MSG_IE_CGAD] +#define msg_ie_cgsa msg_ie_vec[UNI_MSG_IE_CGSA] +#define msg_ie_caus msg_ie_vec[UNI_MSG_IE_CAUS] +#define msg_ie_cnid msg_ie_vec[UNI_MSG_IE_CNID] +#define msg_ie_qosp msg_ie_vec[UNI_MSG_IE_QOSP] +#define msg_ie_brpi msg_ie_vec[UNI_MSG_IE_BRPI] +#define msg_ie_rsti msg_ie_vec[UNI_MSG_IE_RSTI] +#define msg_ie_blsh msg_ie_vec[UNI_MSG_IE_BLSH] +#define msg_ie_bnsh msg_ie_vec[UNI_MSG_IE_BNSH] +#define msg_ie_bsdc msg_ie_vec[UNI_MSG_IE_BSDC] +#define msg_ie_trnt msg_ie_vec[UNI_MSG_IE_TRNT] +#define msg_ie_eprf msg_ie_vec[UNI_MSG_IE_EPRF] +#define msg_ie_epst msg_ie_vec[UNI_MSG_IE_EPST] +#define msg_ie_err msg_ie_vec[UNI_MSG_IE_ERR] + + +/* + * Information element header. + */ +struct ie_hdr { + u_char ie_hdr_ident; + u_char ie_hdr_coding; + u_char ie_hdr_flag; + u_char ie_hdr_action; + int ie_hdr_length; + int ie_hdr_err_cause; + struct ie_generic *ie_hdr_next; +}; + +#define UNI_IE_HDR_LEN 4 + +#define UNI_IE_CODE_CCITT 0 +#define UNI_IE_CODE_STD 3 +#define UNI_IE_CODE_MASK 3 +#define UNI_IE_CODE_SHIFT 5 + +#define UNI_IE_FLAG_MASK 1 +#define UNI_IE_FLAG_SHIFT 4 + +#define UNI_IE_ACT_CLEAR 0 +#define UNI_IE_ACT_DIS 1 +#define UNI_IE_ACT_RPRT 2 +#define UNI_IE_ACT_DMSGIGN 5 +#define UNI_IE_ACT_DMSGRPRT 6 +#define UNI_IE_ACT_MASK 7 + + +/* + * ATM AAL parameters information element in internal format. + */ +struct ie_aalp { + int8_t ie_aal_type; + union { + struct aal_type_1_parm { + u_char subtype; + u_char cbr_rate; + u_short multiplier; + u_char clock_recovery; + u_char error_correction; + u_char struct_data_tran; + u_char partial_cells; + } type_1; + struct aal_type_4_parm { + int32_t fwd_max_sdu; + int32_t bkwd_max_sdu; + int32_t mid_range; + u_char mode; + u_char sscs_type; + } type_4; + struct aal_type_5_parm { + int32_t fwd_max_sdu; + int32_t bkwd_max_sdu; + u_char mode; + u_char sscs_type; + } type_5; + struct user_aal_type { + u_char aal_info[4]; + } type_user; + } aal_u; +}; + +#define UNI_IE_AALP_AT_AAL1 1 +#define UNI_IE_AALP_AT_AAL3 3 +#define UNI_IE_AALP_AT_AAL5 5 +#define UNI_IE_AALP_AT_AALU 16 + +#define UNI_IE_AALP_A1_ST_NULL 0 +#define UNI_IE_AALP_A1_ST_VCE 1 +#define UNI_IE_AALP_A1_ST_SCE 2 +#define UNI_IE_AALP_A1_ST_ACE 3 +#define UNI_IE_AALP_A1_ST_HQA 4 +#define UNI_IE_AALP_A1_ST_VID 5 + +#define UNI_IE_AALP_A1_CB_64 1 +#define UNI_IE_AALP_A1_CB_DS1 4 +#define UNI_IE_AALP_A1_CB_DS2 5 +#define UNI_IE_AALP_A1_CB_32064 6 +#define UNI_IE_AALP_A1_CB_DS3 7 +#define UNI_IE_AALP_A1_CB_97728 8 +#define UNI_IE_AALP_A1_CB_E1 16 +#define UNI_IE_AALP_A1_CB_E2 17 +#define UNI_IE_AALP_A1_CB_E3 18 +#define UNI_IE_AALP_A1_CB_139264 19 +#define UNI_IE_AALP_A1_CB_N64 64 + +#define UNI_IE_AALP_A1_CR_NULL 0 +#define UNI_IE_AALP_A1_CR_SRTS 1 +#define UNI_IE_AALP_A1_CR_ACR 2 + +#define UNI_IE_AALP_A1_EC_NULL 0 +#define UNI_IE_AALP_A1_EC_FEC 1 + +#define UNI_IE_AALP_A1_SD_NULL 0 +#define UNI_IE_AALP_A1_SD_SDT 1 + +#define UNI_IE_AALP_A3_R_MASK 1023 +#define UNI_IE_AALP_A3_R_SHIFT 16 + +#define UNI_IE_AALP_A5_M_MSG 1 +#define UNI_IE_AALP_A5_M_STR 2 + +#define UNI_IE_AALP_A5_ST_NULL 0 +#define UNI_IE_AALP_A5_ST_AO 1 +#define UNI_IE_AALP_A5_ST_NAO 2 +#define UNI_IE_AALP_A5_ST_FR 4 + + +/* + * ATM user cell rate information element in internal format. + */ +struct ie_clrt { + int32_t ie_fwd_peak; + int32_t ie_bkwd_peak; + int32_t ie_fwd_peak_01; + int32_t ie_bkwd_peak_01; + int32_t ie_fwd_sust; + int32_t ie_bkwd_sust; + int32_t ie_fwd_sust_01; + int32_t ie_bkwd_sust_01; + int32_t ie_fwd_burst; + int32_t ie_bkwd_burst; + int32_t ie_fwd_burst_01; + int32_t ie_bkwd_burst_01; + int8_t ie_best_effort; + int8_t ie_tm_options; +}; + +#define UNI_IE_CLRT_FWD_PEAK_ID 130 +#define UNI_IE_CLRT_BKWD_PEAK_ID 131 +#define UNI_IE_CLRT_FWD_PEAK_01_ID 132 +#define UNI_IE_CLRT_BKWD_PEAK_01_ID 133 +#define UNI_IE_CLRT_FWD_SUST_ID 136 +#define UNI_IE_CLRT_BKWD_SUST_ID 137 +#define UNI_IE_CLRT_FWD_SUST_01_ID 144 +#define UNI_IE_CLRT_BKWD_SUST_01_ID 145 +#define UNI_IE_CLRT_FWD_BURST_ID 160 +#define UNI_IE_CLRT_BKWD_BURST_ID 161 +#define UNI_IE_CLRT_FWD_BURST_01_ID 176 +#define UNI_IE_CLRT_BKWD_BURST_01_ID 177 +#define UNI_IE_CLRT_BEST_EFFORT_ID 190 +#define UNI_IE_CLRT_TM_OPTIONS_ID 191 + +#define UNI_IE_CLRT_TM_FWD_TAG 0x01 +#define UNI_IE_CLRT_TM_BKWD_TAG 0x02 + + +/* + * Broadband bearer capability information element in internal format. + */ +struct ie_bbcp { + int8_t ie_bearer_class; + int8_t ie_traffic_type; + int8_t ie_timing_req; + int8_t ie_clipping; + int8_t ie_conn_config; +}; + + +#define UNI_IE_BBCP_BC_BCOB_A 1 +#define UNI_IE_BBCP_BC_BCOB_C 3 +#define UNI_IE_BBCP_BC_BCOB_X 16 +#define UNI_IE_BBCP_BC_MASK 0x1F + +#define UNI_IE_BBCP_TT_NIND 0 +#define UNI_IE_BBCP_TT_CBR 1 +#define UNI_IE_BBCP_TT_VBR 2 +#define UNI_IE_BBCP_TT_MASK 3 +#define UNI_IE_BBCP_TT_SHIFT 2 + +#define UNI_IE_BBCP_TR_NIND 0 +#define UNI_IE_BBCP_TR_EER 1 +#define UNI_IE_BBCP_TR_EENR 2 +#define UNI_IE_BBCP_TR_RSVD 3 +#define UNI_IE_BBCP_TR_MASK 3 + +#define UNI_IE_BBCP_SC_NSUS 0 +#define UNI_IE_BBCP_SC_SUS 1 +#define UNI_IE_BBCP_SC_MASK 3 +#define UNI_IE_BBCP_SC_SHIFT 5 + +#define UNI_IE_BBCP_CC_PP 0 +#define UNI_IE_BBCP_CC_PM 1 +#define UNI_IE_BBCP_CC_MASK 3 + + +/* + * Broadband high layer information information element in internal + * format. + */ +struct ie_bhli { + int8_t ie_type; + u_char ie_info[8]; +}; + +#define UNI_IE_BHLI_TYPE_ISO 0 +#define UNI_IE_BHLI_TYPE_USER 1 +#define UNI_IE_BHLI_TYPE_HLP 2 +#define UNI_IE_BHLI_TYPE_VSA 3 + +#define UNI_IE_BHLI_HLP_LEN 4 +#define UNI_IE_BHLI_VSA_LEN 7 + + +/* + * Broadband low-layer information information element in internal + * format. + */ +struct ie_blli { + int8_t ie_l1_id; + int8_t ie_l2_id; + int8_t ie_l2_mode; + int8_t ie_l2_q933_use; + int8_t ie_l2_window; + int8_t ie_l2_user_proto; + int8_t ie_l3_id; + int8_t ie_l3_mode; + int8_t ie_l3_packet_size; + int8_t ie_l3_window; + int8_t ie_l3_user_proto; + int16_t ie_l3_ipi; + int8_t ie_l3_snap_id; + u_char ie_l3_oui[3]; + u_char ie_l3_pid[2]; +}; + +#define UNI_IE_BLLI_L1_ID 1 +#define UNI_IE_BLLI_L2_ID 2 +#define UNI_IE_BLLI_L3_ID 3 +#define UNI_IE_BLLI_LID_MASK 3 +#define UNI_IE_BLLI_LID_SHIFT 5 +#define UNI_IE_BLLI_LP_MASK 31 + +#define UNI_IE_BLLI_L2P_ISO1745 1 +#define UNI_IE_BLLI_L2P_Q921 2 +#define UNI_IE_BLLI_L2P_X25L 6 +#define UNI_IE_BLLI_L2P_X25M 7 +#define UNI_IE_BLLI_L2P_LAPB 8 +#define UNI_IE_BLLI_L2P_HDLC1 9 +#define UNI_IE_BLLI_L2P_HDLC2 10 +#define UNI_IE_BLLI_L2P_HDLC3 11 +#define UNI_IE_BLLI_L2P_LLC 12 +#define UNI_IE_BLLI_L2P_X75 13 +#define UNI_IE_BLLI_L2P_Q922 14 +#define UNI_IE_BLLI_L2P_USER 16 +#define UNI_IE_BLLI_L2P_ISO7776 17 + +#define UNI_IE_BLLI_L2MODE_NORM 1 +#define UNI_IE_BLLI_L2MODE_EXT 2 +#define UNI_IE_BLLI_L2MODE_SHIFT 5 +#define UNI_IE_BLLI_L2MODE_MASK 3 + +#define UNI_IE_BLLI_Q933_ALT 0 + +#define UNI_IE_BLLI_L3P_X25 6 +#define UNI_IE_BLLI_L3P_ISO8208 7 +#define UNI_IE_BLLI_L3P_ISO8878 8 +#define UNI_IE_BLLI_L3P_ISO8473 9 +#define UNI_IE_BLLI_L3P_T70 10 +#define UNI_IE_BLLI_L3P_ISO9577 11 +#define UNI_IE_BLLI_L3P_USER 16 + +#define UNI_IE_BLLI_L3MODE_NORM 1 +#define UNI_IE_BLLI_L3MODE_EXT 2 +#define UNI_IE_BLLI_L3MODE_SHIFT 5 +#define UNI_IE_BLLI_L3MODE_MASK 3 + +#define UNI_IE_BLLI_L3PS_16 4 +#define UNI_IE_BLLI_L3PS_32 5 +#define UNI_IE_BLLI_L3PS_64 6 +#define UNI_IE_BLLI_L3PS_128 7 +#define UNI_IE_BLLI_L3PS_256 8 +#define UNI_IE_BLLI_L3PS_512 9 +#define UNI_IE_BLLI_L3PS_1024 10 +#define UNI_IE_BLLI_L3PS_2048 11 +#define UNI_IE_BLLI_L3PS_4096 12 +#define UNI_IE_BLLI_L3PS_MASK 15 + +#define UNI_IE_BLLI_L3IPI_SHIFT 6 +#define UNI_IE_BLLI_L3IPI_SNAP 0x80 + + +/* + * Call state information element in internal format. + */ +struct ie_clst { + int8_t ie_state; +}; + +#define UNI_IE_CLST_STATE_U0 0 +#define UNI_IE_CLST_STATE_U1 1 +#define UNI_IE_CLST_STATE_U3 3 +#define UNI_IE_CLST_STATE_U6 6 +#define UNI_IE_CLST_STATE_U8 8 +#define UNI_IE_CLST_STATE_U9 9 +#define UNI_IE_CLST_STATE_U10 10 +#define UNI_IE_CLST_STATE_U11 11 +#define UNI_IE_CLST_STATE_U12 12 + +#define UNI_IE_CLST_STATE_N0 0 +#define UNI_IE_CLST_STATE_N1 1 +#define UNI_IE_CLST_STATE_N3 3 +#define UNI_IE_CLST_STATE_N6 6 +#define UNI_IE_CLST_STATE_N8 8 +#define UNI_IE_CLST_STATE_N9 9 +#define UNI_IE_CLST_STATE_N10 10 +#define UNI_IE_CLST_STATE_N11 11 +#define UNI_IE_CLST_STATE_N12 12 + +#define UNI_IE_CLST_GLBL_REST0 0x00 +#define UNI_IE_CLST_GLBL_REST1 0x3d +#define UNI_IE_CLST_GLBL_REST2 0x3e + +#define UNI_IE_CLST_STATE_MASK 0x3f + + +/* + * Called party number information element in internal format. + */ +struct ie_cdad { + int8_t ie_type; + int8_t ie_plan; + Atm_addr ie_addr; +}; + +#define UNI_IE_CDAD_TYPE_UNK 0 +#define UNI_IE_CDAD_TYPE_INTL 1 +#define UNI_IE_CDAD_TYPE_MASK 7 +#define UNI_IE_CDAD_TYPE_SHIFT 4 + +#define UNI_IE_CDAD_PLAN_E164 1 +#define UNI_IE_CDAD_PLAN_NSAP 2 +#define UNI_IE_CDAD_PLAN_MASK 15 + + +/* + * Called party subaddress information element in internal format. + */ +struct ie_cdsa { + Atm_addr ie_addr; +}; + +#define UNI_IE_CDSA_TYPE_NSAP 0 +#define UNI_IE_CDSA_TYPE_AESA 1 +#define UNI_IE_CDSA_TYPE_MASK 7 +#define UNI_IE_CDSA_TYPE_SHIFT 4 + + +/* + * Calling party number information element in internal format. + */ +struct ie_cgad { + int8_t ie_type; + int8_t ie_plan; + int8_t ie_pres_ind; + int8_t ie_screen_ind; + Atm_addr ie_addr; +}; + +#define UNI_IE_CGAD_TYPE_UNK 0 +#define UNI_IE_CGAD_TYPE_INTL 1 +#define UNI_IE_CGAD_TYPE_MASK 7 +#define UNI_IE_CGAD_TYPE_SHIFT 4 + +#define UNI_IE_CGAD_PLAN_E164 1 +#define UNI_IE_CGAD_PLAN_NSAP 2 +#define UNI_IE_CGAD_PLAN_MASK 15 + +#define UNI_IE_CGAD_PRES_ALLOW 0 +#define UNI_IE_CGAD_PRES_RSTR 1 +#define UNI_IE_CGAD_PRES_NNA 2 +#define UNI_IE_CGAD_PRES_RSVD 3 +#define UNI_IE_CGAD_PRES_MASK 3 +#define UNI_IE_CGAD_PRES_SHIFT 5 + +#define UNI_IE_CGAD_SCR_UNS 0 +#define UNI_IE_CGAD_SCR_UVP 1 +#define UNI_IE_CGAD_SCR_UVF 2 +#define UNI_IE_CGAD_SCR_NET 3 +#define UNI_IE_CGAD_SCR_MASK 3 + + +/* + * Calling party subaddress information element in internal format. + */ +struct ie_cgsa { + Atm_addr ie_addr; +}; + +#define UNI_IE_CGSA_TYPE_NSAP 0 +#define UNI_IE_CGSA_TYPE_AESA 1 +#define UNI_IE_CGSA_TYPE_MASK 7 +#define UNI_IE_CGSA_TYPE_SHIFT 4 + + +/* + * Cause information element in internal format. + */ +#define UNI_IE_CAUS_MAX_ID 24 +#define UNI_IE_CAUS_MAX_QOS_SUB 24 +struct ie_caus { + int8_t ie_loc; + int8_t ie_cause; + int8_t ie_diag_len; + u_int8_t ie_diagnostic[24]; +}; + +#define UNI_IE_CAUS_LOC_USER 0 +#define UNI_IE_CAUS_LOC_PRI_LCL 1 +#define UNI_IE_CAUS_LOC_PUB_LCL 2 +#define UNI_IE_CAUS_LOC_TRANSIT 3 +#define UNI_IE_CAUS_LOC_PUB_RMT 4 +#define UNI_IE_CAUS_LOC_PRI_RMT 5 +#define UNI_IE_CAUS_LOC_INTL 7 +#define UNI_IE_CAUS_LOC_BEYOND 10 +#define UNI_IE_CAUS_LOC_MASK 15 + +#define UNI_IE_CAUS_UN_NS_SHIFT 3 +#define UNI_IE_CAUS_UN_NS_MASK 1 + +#define UNI_IE_CAUS_UN_NA_SHIFT 2 +#define UNI_IE_CAUS_UN_NA_MASK 1 + +#define UNI_IE_CAUS_UN_CAU_MASK 3 + +#define UNI_IE_CAUS_RR_USER 0 +#define UNI_IE_CAUS_RR_IE 1 +#define UNI_IE_CAUS_RR_INSUFF 2 +#define UNI_IE_CAUS_RR_SHIFT 2 +#define UNI_IE_CAUS_RR_MASK 31 + +#define UNI_IE_CAUS_RC_UNK 0 +#define UNI_IE_CAUS_RC_PERM 1 +#define UNI_IE_CAUS_RC_TRANS 2 +#define UNI_IE_CAUS_RC_MASK 3 + +/* + * Cause codes from UNI 3.0, section 5.4.5.15 + */ +#define UNI_IE_CAUS_UNO 1 /* Unallocated number */ +#define UNI_IE_CAUS_NOTROUTE 2 /* No route to transit net */ +#define UNI_IE_CAUS_NODROUTE 3 /* No route to destination */ +#define UNI_IE_CAUS_BAD_VCC 10 /* VPI/VCI unacceptable */ +#define UNI_IE_CAUS_NORM 16 /* Normal call clearing */ +#define UNI_IE_CAUS_BUSY 17 /* User busy */ +#define UNI_IE_CAUS_NORSP 18 /* No user responding */ +#define UNI_IE_CAUS_REJECT 21 /* Call rejected */ +#define UNI_IE_CAUS_CHANGED 22 /* Number changed */ +#define UNI_IE_CAUS_CLIR 23 /* User rejects CLIR */ +#define UNI_IE_CAUS_DORDER 27 /* Dest out of order */ +#define UNI_IE_CAUS_INVNO 28 /* Invalid number format */ +#define UNI_IE_CAUS_SENQ 30 /* Rsp to Status Enquiry */ +#define UNI_IE_CAUS_NORM_UNSP 31 /* Normal, unspecified */ +#define UNI_IE_CAUS_NA_VCC 35 /* VCC not available */ +#define UNI_IE_CAUS_ASSIGN_VCC 36 /* VPCI/VCI assignment failure */ +#define UNI_IE_CAUS_NORDER 38 /* Network out of order */ +#define UNI_IE_CAUS_TEMP 41 /* Temporary failure */ +#define UNI_IE_CAUS_DISCARD 43 /* Access info discarded */ +#define UNI_IE_CAUS_NO_VCC 45 /* No VPI/VCI available */ +#define UNI_IE_CAUS_UNAVAIL 47 /* Resource unavailable */ +#define UNI_IE_CAUS_NO_QOS 49 /* QoS unavailable */ +#define UNI_IE_CAUS_NO_CR 51 /* User cell rate not avail */ +#define UNI_IE_CAUS_NO_BC 57 /* Bearer capability not auth */ +#define UNI_IE_CAUS_NA_BC 58 /* Bearer capability n/a */ +#define UNI_IE_CAUS_SERVICE 63 /* Service or opt not avail */ +#define UNI_IE_CAUS_NI_BC 65 /* Bearer cap not implemented */ +#define UNI_IE_CAUS_COMB 73 /* Unsupported combination */ +#define UNI_IE_CAUS_CREF 81 /* Invalid call reference */ +#define UNI_IE_CAUS_CEXIST 82 /* Channel does not exist */ +#define UNI_IE_CAUS_IDEST 88 /* Incompatible destination */ +#define UNI_IE_CAUS_ENDPT 89 /* Invalid endpoint reference */ +#define UNI_IE_CAUS_TRNET 91 /* Invalid transit net */ +#define UNI_IE_CAUS_APPEND 92 /* Too many pending add party */ +#define UNI_IE_CAUS_UAAL 93 /* AAL parms can't be supp */ +#define UNI_IE_CAUS_MISSING 96 /* Mandatory IE missing */ +#define UNI_IE_CAUS_MTEXIST 97 /* Message type nonexistent */ +#define UNI_IE_CAUS_IEEXIST 99 /* IE type nonexistent */ +#define UNI_IE_CAUS_IECONTENT 100 /* IE content invalid */ +#define UNI_IE_CAUS_STATE 101 /* Message incomp with state */ +#define UNI_IE_CAUS_TIMER 102 /* Recovery on timer expire */ +#define UNI_IE_CAUS_LEN 104 /* Incorrect message length */ +#define UNI_IE_CAUS_PROTO 111 /* Protocol error */ + + +/* + * Connection identifier information element in internal format. + */ +struct ie_cnid { + int8_t ie_vp_sig; + int8_t ie_pref_excl; + u_short ie_vpci; + u_short ie_vci; +}; + +#define UNI_IE_CNID_VPSIG_MASK 3 +#define UNI_IE_CNID_VPSIG_SHIFT 3 +#define UNI_IE_CNID_PREX_MASK 7 + +#define UNI_IE_CNID_MIN_VCI 32 + + +/* + * Quality of service parameter information element in internal format. + */ +struct ie_qosp { + int8_t ie_fwd_class; + int8_t ie_bkwd_class; +}; + +#define UNI_IE_QOSP_FWD_CLASS_0 0 +#define UNI_IE_QOSP_FWD_CLASS_1 1 +#define UNI_IE_QOSP_FWD_CLASS_2 2 +#define UNI_IE_QOSP_FWD_CLASS_3 3 +#define UNI_IE_QOSP_FWD_CLASS_4 4 + +#define UNI_IE_QOSP_BKWD_CLASS_0 0 +#define UNI_IE_QOSP_BKWD_CLASS_1 1 +#define UNI_IE_QOSP_BKWD_CLASS_2 2 +#define UNI_IE_QOSP_BKWD_CLASS_3 3 +#define UNI_IE_QOSP_BKWD_CLASS_4 4 + + +/* + * Broadband repeat indicator information element in internal format. + */ +struct ie_brpi { + int8_t ie_ind; +}; + +#define UNI_IE_BRPI_PRI_LIST 2 +#define UNI_IE_BRPI_IND_MASK 15 + + +/* + * Restart indicator information element in internal format. + */ +struct ie_rsti { + int8_t ie_class; +}; + +#define UNI_IE_RSTI_IND_VC 0 +#define UNI_IE_RSTI_ALL_VC 2 +#define UNI_IE_RSTI_CLASS_MASK 3 + + +/* + * Broadband locking shift information element in internal format. + */ +struct ie_blsh { + int8_t ie_dummy; +}; + + +/* + * Broadband non-locking shift information element in internal format. + */ +struct ie_bnsh { + int8_t ie_dummy; +}; + + +/* + * Broadband sending complete information element in internal format. + */ +struct ie_bsdc { + int8_t ie_ind; +}; + +#define UNI_IE_BSDC_IND 0x21 + + +/* + * Transit net selection information element in internal format. + */ +struct ie_trnt { + int8_t ie_id_type; + int8_t ie_id_plan; + u_char ie_id_len; + u_char ie_id[4]; +}; + +#define UNI_IE_TRNT_IDT_MASK 7 +#define UNI_IE_TRNT_IDT_SHIFT 4 +#define UNI_IE_TRNT_IDP_MASK 15 + +#define UNI_IE_TRNT_IDT_NATL 2 +#define UNI_IE_TRNT_IDP_CIC 1 + + +/* + * Endpoint reference information element in internal format. + */ +struct ie_eprf { + int8_t ie_type; + int16_t ie_id; +}; + +#define UNI_IE_EPRF_LDI 0 + + +/* + * Endpoint state information element in internal format. + */ +struct ie_epst { + int8_t ie_state; +}; + +#define UNI_IE_EPST_NULL 0 +#define UNI_IE_EPST_API 1 +#define UNI_IE_EPST_APR 6 +#define UNI_IE_EPST_DPI 11 +#define UNI_IE_EPST_DPR 12 +#define UNI_IE_EPST_ACTIVE 10 +#define UNI_IE_EPST_STATE_MASK 0x3F + + +/* + * Generic information element + */ +struct ie_generic { + struct ie_hdr ie_hdr; + union { + struct ie_aalp ie_aalp; + struct ie_clrt ie_clrt; + struct ie_bbcp ie_bbcp; + struct ie_bhli ie_bhli; + struct ie_blli ie_blli; + struct ie_clst ie_clst; + struct ie_cdad ie_cdad; + struct ie_cdsa ie_cdsa; + struct ie_cgad ie_cgad; + struct ie_cgsa ie_cgsa; + struct ie_caus ie_caus; + struct ie_cnid ie_cnid; + struct ie_qosp ie_qosp; + struct ie_brpi ie_brpi; + struct ie_rsti ie_rsti; + struct ie_blsh ie_blsh; + struct ie_bnsh ie_bnsh; + struct ie_bsdc ie_bsdc; + struct ie_trnt ie_trnt; + struct ie_eprf ie_eprf; + struct ie_epst ie_epst; + } ie_u; +}; + +#define ie_ident ie_hdr.ie_hdr_ident +#define ie_coding ie_hdr.ie_hdr_coding +#define ie_flag ie_hdr.ie_hdr_flag +#define ie_action ie_hdr.ie_hdr_action +#define ie_length ie_hdr.ie_hdr_length +#define ie_err_cause ie_hdr.ie_hdr_err_cause +#define ie_next ie_hdr.ie_hdr_next + +#define ie_aalp_aal_type ie_u.ie_aalp.ie_aal_type +#define ie_aalp_1_subtype ie_u.ie_aalp.aal_u.type_1.subtype +#define ie_aalp_1_cbr_rate ie_u.ie_aalp.aal_u.type_1.cbr_rate +#define ie_aalp_1_multiplier ie_u.ie_aalp.aal_u.type_1.multiplier +#define ie_aalp_1_clock_recovery ie_u.ie_aalp.aal_u.type_1.clock_recovery +#define ie_aalp_1_error_correction ie_u.ie_aalp.aal_u.type_1.error_correction +#define ie_aalp_1_struct_data_tran ie_u.ie_aalp.aal_u.type_1.struct_data_tran +#define ie_aalp_1_partial_cells ie_u.ie_aalp.aal_u.type_1.partial_cells + +#define ie_aalp_4_fwd_max_sdu ie_u.ie_aalp.aal_u.type_4.fwd_max_sdu +#define ie_aalp_4_bkwd_max_sdu ie_u.ie_aalp.aal_u.type_4.bkwd_max_sdu +#define ie_aalp_4_mid_range ie_u.ie_aalp.aal_u.type_4.mid_range +#define ie_aalp_4_mode ie_u.ie_aalp.aal_u.type_4.mode +#define ie_aalp_4_sscs_type ie_u.ie_aalp.aal_u.type_4.sscs_type + +#define ie_aalp_5_fwd_max_sdu ie_u.ie_aalp.aal_u.type_5.fwd_max_sdu +#define ie_aalp_5_bkwd_max_sdu ie_u.ie_aalp.aal_u.type_5.bkwd_max_sdu +#define ie_aalp_5_mode ie_u.ie_aalp.aal_u.type_5.mode +#define ie_aalp_5_sscs_type ie_u.ie_aalp.aal_u.type_5.sscs_type +#define ie_aalp_user_info ie_u.ie_aalp.aal_u.type_user.aal_info + +#define ie_clrt_fwd_peak ie_u.ie_clrt.ie_fwd_peak +#define ie_clrt_bkwd_peak ie_u.ie_clrt.ie_bkwd_peak +#define ie_clrt_fwd_peak_01 ie_u.ie_clrt.ie_fwd_peak_01 +#define ie_clrt_bkwd_peak_01 ie_u.ie_clrt.ie_bkwd_peak_01 +#define ie_clrt_fwd_sust ie_u.ie_clrt.ie_fwd_sust +#define ie_clrt_bkwd_sust ie_u.ie_clrt.ie_bkwd_sust +#define ie_clrt_fwd_sust_01 ie_u.ie_clrt.ie_fwd_sust_01 +#define ie_clrt_bkwd_sust_01 ie_u.ie_clrt.ie_bkwd_sust_01 +#define ie_clrt_fwd_burst ie_u.ie_clrt.ie_fwd_burst +#define ie_clrt_bkwd_burst ie_u.ie_clrt.ie_bkwd_burst +#define ie_clrt_fwd_burst_01 ie_u.ie_clrt.ie_fwd_burst_01 +#define ie_clrt_bkwd_burst_01 ie_u.ie_clrt.ie_bkwd_burst_01 +#define ie_clrt_best_effort ie_u.ie_clrt.ie_best_effort +#define ie_clrt_tm_options ie_u.ie_clrt.ie_tm_options + +#define ie_bbcp_bearer_class ie_u.ie_bbcp.ie_bearer_class +#define ie_bbcp_traffic_type ie_u.ie_bbcp.ie_traffic_type +#define ie_bbcp_timing_req ie_u.ie_bbcp.ie_timing_req +#define ie_bbcp_clipping ie_u.ie_bbcp.ie_clipping +#define ie_bbcp_conn_config ie_u.ie_bbcp.ie_conn_config + +#define ie_bhli_type ie_u.ie_bhli.ie_type +#define ie_bhli_info ie_u.ie_bhli.ie_info + +#define ie_blli_l1_id ie_u.ie_blli.ie_l1_id +#define ie_blli_l2_id ie_u.ie_blli.ie_l2_id +#define ie_blli_l2_mode ie_u.ie_blli.ie_l2_mode +#define ie_blli_l2_q933_use ie_u.ie_blli.ie_l2_q933_use +#define ie_blli_l2_window ie_u.ie_blli.ie_l2_window +#define ie_blli_l2_user_proto ie_u.ie_blli.ie_l2_user_proto +#define ie_blli_l3_id ie_u.ie_blli.ie_l3_id +#define ie_blli_l3_mode ie_u.ie_blli.ie_l3_mode +#define ie_blli_l3_packet_size ie_u.ie_blli.ie_l3_packet_size +#define ie_blli_l3_window ie_u.ie_blli.ie_l3_window +#define ie_blli_l3_user_proto ie_u.ie_blli.ie_l3_user_proto +#define ie_blli_l3_ipi ie_u.ie_blli.ie_l3_ipi +#define ie_blli_l3_snap_id ie_u.ie_blli.ie_l3_snap_id +#define ie_blli_l3_oui ie_u.ie_blli.ie_l3_oui +#define ie_blli_l3_pid ie_u.ie_blli.ie_l3_pid + +#define ie_clst_state ie_u.ie_clst.ie_state + +#define ie_cdad_type ie_u.ie_cdad.ie_type +#define ie_cdad_plan ie_u.ie_cdad.ie_plan +#define ie_cdad_addr ie_u.ie_cdad.ie_addr + +#define ie_cdsa_addr ie_u.ie_cdsa.ie_addr + +#define ie_cgad_type ie_u.ie_cgad.ie_type +#define ie_cgad_plan ie_u.ie_cgad.ie_plan +#define ie_cgad_pres_ind ie_u.ie_cgad.ie_pres_ind +#define ie_cgad_screen_ind ie_u.ie_cgad.ie_screen_ind +#define ie_cgad_addr ie_u.ie_cgad.ie_addr + +#define ie_cgsa_addr ie_u.ie_cgsa.ie_addr + +#define ie_caus_loc ie_u.ie_caus.ie_loc +#define ie_caus_cause ie_u.ie_caus.ie_cause +#define ie_caus_diag_len ie_u.ie_caus.ie_diag_len +#define ie_caus_diagnostic ie_u.ie_caus.ie_diagnostic + +#define ie_cnid_vp_sig ie_u.ie_cnid.ie_vp_sig +#define ie_cnid_pref_excl ie_u.ie_cnid.ie_pref_excl +#define ie_cnid_vpci ie_u.ie_cnid.ie_vpci +#define ie_cnid_vci ie_u.ie_cnid.ie_vci + +#define ie_qosp_fwd_class ie_u.ie_qosp.ie_fwd_class +#define ie_qosp_bkwd_class ie_u.ie_qosp.ie_bkwd_class + +#define ie_brpi_ind ie_u.ie_brpi.ie_ind + +#define ie_rsti_class ie_u.ie_rsti.ie_class + +#define ie_bsdc_ind ie_u.ie_bsdc.ie_ind + +#define ie_trnt_id_type ie_u.ie_trnt.ie_id_type +#define ie_trnt_id_plan ie_u.ie_trnt.ie_id_plan +#define ie_trnt_id_len ie_u.ie_trnt.ie_id_len +#define ie_trnt_id ie_u.ie_trnt.ie_id + +#define ie_eprf_type ie_u.ie_eprf.ie_type +#define ie_eprf_id ie_u.ie_eprf.ie_id + +#define ie_epst_state ie_u.ie_epst.ie_state + +/* + * Macro to add an IE to the end of a list of IEs + */ +#define MSG_IE_ADD(m, i, ind) \ + if (m->msg_ie_vec[ind]) { \ + struct ie_generic *_iep = msg->msg_ie_vec[ind]; \ + while (_iep->ie_next) { \ + _iep = _iep->ie_next; \ + } \ + _iep->ie_next = i; \ + } else { \ + m->msg_ie_vec[ind] = i; \ + } + +#endif /* _UNI_SIG_MSG_H */ diff --git a/sys/netatm/uni/unisig_print.c b/sys/netatm/uni/unisig_print.c new file mode 100644 index 0000000..f335ce4 --- /dev/null +++ b/sys/netatm/uni/unisig_print.c @@ -0,0 +1,877 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: unisig_print.c,v 1.9 1998/08/26 23:29:23 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Print Q.2931 messages + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_print.c,v 1.9 1998/08/26 23:29:23 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/unisig.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/unisig_msg.h> +#include <netatm/uni/unisig_print.h> + + +/* + * Local declarations + */ +struct type_name { + char *name; + u_char type; +}; + + +/* + * Local functions + */ +static char * find_type __P((struct type_name *, u_char)); +static void usp_print_atm_addr __P((Atm_addr *)); +static void usp_print_ie __P((struct ie_generic *)); +static void usp_print_ie_aalp __P((struct ie_generic *)); +static void usp_print_ie_clrt __P((struct ie_generic *)); +static void usp_print_ie_bbcp __P((struct ie_generic *)); +static void usp_print_ie_bhli __P((struct ie_generic *)); +static void usp_print_ie_blli __P((struct ie_generic *)); +static void usp_print_ie_clst __P((struct ie_generic *)); +static void usp_print_ie_cdad __P((struct ie_generic *)); +static void usp_print_ie_cdsa __P((struct ie_generic *)); +static void usp_print_ie_cgad __P((struct ie_generic *)); +static void usp_print_ie_cgsa __P((struct ie_generic *)); +static void usp_print_ie_caus __P((struct ie_generic *)); +static void usp_print_ie_cnid __P((struct ie_generic *)); +static void usp_print_ie_qosp __P((struct ie_generic *)); +static void usp_print_ie_brpi __P((struct ie_generic *)); +static void usp_print_ie_rsti __P((struct ie_generic *)); +static void usp_print_ie_blsh __P((struct ie_generic *)); +static void usp_print_ie_bnsh __P((struct ie_generic *)); +static void usp_print_ie_bsdc __P((struct ie_generic *)); +static void usp_print_ie_trnt __P((struct ie_generic *)); +static void usp_print_ie_eprf __P((struct ie_generic *)); +static void usp_print_ie_epst __P((struct ie_generic *)); + + +/* + * Values for Q.2931 message type. + */ +static struct type_name msg_types[] = { + { "Call proceeding", 0x02 }, + { "Connect", 0x07 }, + { "Connect ACK", 0x0F }, + { "Setup", 0x05 }, + { "Release", 0x4D }, + { "Release complete", 0x5A }, + { "Restart", 0x46 }, + { "Restart ACK", 0x4E }, + { "Status", 0x7D }, + { "Status enquiry", 0x75 }, + { "Add party", 0x80 }, + { "Add party ACK", 0x81 }, + { "Add party reject", 0x82 }, + { "Drop party", 0x83 }, + { "Drop party ACK", 0x84 }, + {0, 0} +}; + + +/* + * Values for information element identifier. + */ +static struct type_name ie_types[] = { + { "Cause", 0x08 }, + { "Call state", 0x14 }, + { "Endpoint reference", 0x54 }, + { "Endpoint state", 0x55 }, + { "ATM AAL parameters", 0x58 }, + { "ATM user cell rate", 0x59 }, + { "Connection ID", 0x5A }, + { "QoS parameter", 0x5C }, + { "Broadband high layer info", 0x5D }, + { "Broadband bearer capability", 0x5E }, + { "Broadband low layer info", 0x5F }, + { "Broadband locking shift", 0x60 }, + { "Broadband non-locking shift", 0x61 }, + { "Broadband sending complete", 0x62 }, + { "Broadband repeat indicator", 0x63 }, + { "Calling party number", 0x6C }, + { "Calling party subaddress", 0x6D }, + { "Called party number", 0x70 }, + { "Called party subaddress", 0x71 }, + { "Transit net selection", 0x78 }, + { "Restart indicator", 0x79 }, + { 0, 0 } +}; + + +/* + * Search a name - type translation table + * + * Arguments: + * tbl a pointer to the table to search + * type the type to look for + * + * Returns: + * name a pointer to a character string with the name + * + */ +static char * +find_type(tbl, type) + struct type_name *tbl; + u_char type; +{ + while (type != tbl->type && tbl->name) + tbl++; + + if (tbl->name) + return(tbl->name); + else + return("-"); +} + + +/* + * Print an ATM address + * + * Arguments: + * p pointer to a Atm_address + * + * Returns: + * none + * + */ +static void +usp_print_atm_addr(p) + Atm_addr *p; +{ + char *cp; + + cp = unisig_addr_print(p); + printf("%s", cp); +} + + +/* + * Print a Q.2931 message structure + * + * Arguments: + * msg pointer to the message to print + * + * Returns: + * None + * + */ +void +usp_print_msg(msg, dir) + struct unisig_msg *msg; + int dir; +{ + char *name; + int i; + struct ie_generic *ie, *inxt; + + name = find_type(msg_types, msg->msg_type); + switch (dir) { + case UNISIG_MSG_IN: + printf("Received "); + break; + case UNISIG_MSG_OUT: + printf("Sent "); + break; + } + printf("message: %s (%x)\n", name, msg->msg_type); + printf(" Call reference: 0x%x\n", msg->msg_call_ref); +#ifdef LONG_PRINT + printf(" Message type flag: 0x%x\n", msg->msg_type_flag); + printf(" Message type action: 0x%x\n", msg->msg_type_action); + printf(" Message length: %d\n", msg->msg_length); + for (i=0; i<UNI_MSG_IE_CNT; i++) { + ie = msg->msg_ie_vec[i]; + while (ie) { + inxt = ie->ie_next; + usp_print_ie(ie); + ie = inxt; + } + } +#else + for (i=0; i<UNI_MSG_IE_CNT; i++) + { + ie = msg->msg_ie_vec[i]; + while (ie) { + inxt = ie->ie_next; + name = find_type(ie_types, ie->ie_ident); + if (ie->ie_ident == UNI_IE_CAUS || + ie->ie_ident == UNI_IE_RSTI || + ie->ie_ident == UNI_IE_CLST) { + usp_print_ie(ie); + } else { + printf(" Information element: %s (0x%x)\n", + name, ie->ie_ident); + } + ie = inxt; + } + } +#endif +} + + +/* + * Print a Q.2931 information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie(ie) + struct ie_generic *ie; +{ + char *name; + + while (ie) { + name = find_type(ie_types, ie->ie_ident); + printf(" Information element: %s (0x%x)\n", + name, ie->ie_ident); +#ifdef LONG_PRINT + printf(" Coding: 0x%x\n", + ie->ie_coding); + printf(" Flag: 0x%x\n", ie->ie_flag); + printf(" Action: 0x%x\n", + ie->ie_action); + printf(" Length: %d\n", ie->ie_length); +#endif + + switch (ie->ie_ident) { + case UNI_IE_AALP: + usp_print_ie_aalp(ie); + break; + case UNI_IE_CLRT: + usp_print_ie_clrt(ie); + break; + case UNI_IE_BBCP: + usp_print_ie_bbcp(ie); + break; + case UNI_IE_BHLI: + usp_print_ie_bhli(ie); + break; + case UNI_IE_BLLI: + usp_print_ie_blli(ie); + break; + case UNI_IE_CLST: + usp_print_ie_clst(ie); + break; + case UNI_IE_CDAD: + usp_print_ie_cdad(ie); + break; + case UNI_IE_CDSA: + usp_print_ie_cdsa(ie); + break; + case UNI_IE_CGAD: + usp_print_ie_cgad(ie); + break; + case UNI_IE_CGSA: + usp_print_ie_cgsa(ie); + break; + case UNI_IE_CAUS: + usp_print_ie_caus(ie); + break; + case UNI_IE_CNID: + usp_print_ie_cnid(ie); + break; + case UNI_IE_QOSP: + usp_print_ie_qosp(ie); + break; + case UNI_IE_BRPI: + usp_print_ie_brpi(ie); + break; + case UNI_IE_RSTI: + usp_print_ie_rsti(ie); + break; + case UNI_IE_BLSH: + usp_print_ie_blsh(ie); + break; + case UNI_IE_BNSH: + usp_print_ie_bnsh(ie); + break; + case UNI_IE_BSDC: + usp_print_ie_bsdc(ie); + break; + case UNI_IE_TRNT: + usp_print_ie_trnt(ie); + break; + case UNI_IE_EPRF: + usp_print_ie_eprf(ie); + break; + case UNI_IE_EPST: + usp_print_ie_epst(ie); + break; + } + ie = ie->ie_next; + } +} + + +/* + * Print an AAL parameters information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_aalp(ie) + struct ie_generic *ie; +{ + printf(" AAL type: %d\n", ie->ie_aalp_aal_type); + switch(ie->ie_aalp_aal_type) { + case UNI_IE_AALP_AT_AAL1: + printf(" Subtype: 0x%x\n", + ie->ie_aalp_1_subtype); + printf(" CBR rate: 0x%x\n", + ie->ie_aalp_1_cbr_rate); + printf(" Multiplier: 0x%x\n", + ie->ie_aalp_1_multiplier); + printf(" Clock rcvry: 0x%x\n", + ie->ie_aalp_1_clock_recovery); + printf(" Err corr: 0x%x\n", + ie->ie_aalp_1_error_correction); + printf(" Struct data: 0x%x\n", + ie->ie_aalp_1_struct_data_tran); + printf(" Partial cells: 0x%x\n", + ie->ie_aalp_1_partial_cells); + break; + case UNI_IE_AALP_AT_AAL3: + printf(" Fwd max SDU: %d\n", + ie->ie_aalp_4_fwd_max_sdu); + printf(" Bkwd max SDU: %d\n", + ie->ie_aalp_4_bkwd_max_sdu); + printf(" MID range: %d\n", + ie->ie_aalp_4_mid_range); + printf(" Mode: 0x%x\n", + ie->ie_aalp_4_mode); + printf(" SSCS type: 0x%x\n", + ie->ie_aalp_4_sscs_type); + break; + case UNI_IE_AALP_AT_AAL5: + printf(" Fwd max SDU: %d\n", + ie->ie_aalp_5_fwd_max_sdu); + printf(" Bkwd max SDU: %d\n", + ie->ie_aalp_5_bkwd_max_sdu); + printf(" Mode: 0x%x\n", + ie->ie_aalp_5_mode); + printf(" SSCS type: 0x%x\n", + ie->ie_aalp_5_sscs_type); + break; + case UNI_IE_AALP_AT_AALU: + printf(" User info: 0x%x %x %x %x\n", + ie->ie_aalp_user_info[0], + ie->ie_aalp_user_info[1], + ie->ie_aalp_user_info[2], + ie->ie_aalp_user_info[3]); + break; + } +} + + +/* + * Print a user cell rate information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_clrt(ie) + struct ie_generic *ie; +{ + printf(" Forward peak: %d\n", ie->ie_clrt_fwd_peak); + printf(" Backward peak: %d\n", ie->ie_clrt_bkwd_peak); + printf(" Fwd peak 01: %d\n", ie->ie_clrt_fwd_peak_01); + printf(" Bkwd peak 01: %d\n", ie->ie_clrt_bkwd_peak_01); + printf(" Fwd sust: %d\n", ie->ie_clrt_fwd_sust); + printf(" Bkwd sust: %d\n", ie->ie_clrt_bkwd_sust); + printf(" Fwd sust 01: %d\n", ie->ie_clrt_fwd_sust_01); + printf(" Bkwd sust 01: %d\n", ie->ie_clrt_bkwd_sust_01); + printf(" Fwd burst: %d\n", ie->ie_clrt_fwd_burst); + printf(" Bkwd burst: %d\n", ie->ie_clrt_bkwd_burst); + printf(" Fwd burst 01: %d\n", ie->ie_clrt_fwd_burst_01); + printf(" Bkwd burst 01: %d\n", + ie->ie_clrt_bkwd_burst_01); + printf(" Best effort: %d\n", ie->ie_clrt_best_effort); + printf(" TM optons: 0x%x\n", + ie->ie_clrt_tm_options); +} + + +/* + * Print a broadband bearer capability information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_bbcp(ie) + struct ie_generic *ie; +{ + printf(" Bearer class: 0x%x\n", + ie->ie_bbcp_bearer_class); + printf(" Traffic type: 0x%x\n", + ie->ie_bbcp_traffic_type); + printf(" Timing req: 0x%x\n", + ie->ie_bbcp_timing_req); + printf(" Clipping: 0x%x\n", ie->ie_bbcp_clipping); + printf(" Conn config: 0x%x\n", + ie->ie_bbcp_conn_config); +} + + +/* + * Print a broadband high layer information information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_bhli(ie) + struct ie_generic *ie; +{ + int i; + + printf(" Type: 0x%x\n", ie->ie_bhli_type); + printf(" HL info: 0x"); + for (i=0; i<ie->ie_length-1; i++) { + printf("%x ", ie->ie_bhli_info[i]); + } + printf("\n"); +} + + +/* + * Print a broadband low-layer information information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_blli(ie) + struct ie_generic *ie; +{ + printf(" Layer 1 ID: 0x%x\n", ie->ie_blli_l1_id); + printf(" Layer 2 ID: 0x%x\n", ie->ie_blli_l2_id); + printf(" Layer 2 mode: 0x%x\n", ie->ie_blli_l2_mode); + printf(" Layer 2 Q.933: 0x%x\n", + ie->ie_blli_l2_q933_use); + printf(" Layer 2 win: 0x%x\n", + ie->ie_blli_l2_window); + printf(" Layer 2 user: 0x%x\n", + ie->ie_blli_l2_user_proto); + printf(" Layer 3 ID: 0x%x\n", ie->ie_blli_l3_id); + printf(" Layer 3 mode: 0x%x\n", ie->ie_blli_l3_mode); + printf(" Layer 3 pkt: 0x%x\n", + ie->ie_blli_l3_packet_size); + printf(" Layer 3 win: 0x%x\n", + ie->ie_blli_l3_window); + printf(" Layer 3 user: 0x%x\n", + ie->ie_blli_l3_user_proto); + printf(" Layer 3 IPI: 0x%x\n", ie->ie_blli_l3_ipi); + printf(" Layer 3 SNAP: 0x%x\n", + ie->ie_blli_l3_snap_id); + printf(" Layer 3 OUI: 0x%x %x %x\n", + ie->ie_blli_l3_oui[0], + ie->ie_blli_l3_oui[1], + ie->ie_blli_l3_oui[2]); + printf(" Layer 3 PID: 0x%x %x\n", + ie->ie_blli_l3_pid[0], + ie->ie_blli_l3_pid[1]); +} + + +/* + * Print a call state information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_clst(ie) + struct ie_generic *ie; +{ + printf(" Call state: %d\n", + ie->ie_clst_state); +} + + +/* + * Print a called party number information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_cdad(ie) + struct ie_generic *ie; +{ + printf(" ATM addr: "); + usp_print_atm_addr(&ie->ie_cdad_addr); + printf("\n"); +} + + +/* + * Print a called party subaddress information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_cdsa(ie) + struct ie_generic *ie; +{ + printf(" ATM subaddr: "); + usp_print_atm_addr(&ie->ie_cdsa_addr); + printf("\n"); +} + + +/* + * Print a calling party number information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_cgad(ie) + struct ie_generic *ie; +{ + printf(" ATM addr: "); + usp_print_atm_addr(&ie->ie_cgad_addr); + printf("\n"); +} + + +/* + * Print a calling party subaddress information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_cgsa(ie) + struct ie_generic *ie; +{ + printf(" ATM subaddr: "); + usp_print_atm_addr(&ie->ie_cgsa_addr); + printf("\n"); +} + + +/* + * Print a cause information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_caus(ie) + struct ie_generic *ie; +{ + int i; + + printf(" Location: %d\n", ie->ie_caus_loc); + printf(" Cause: %d\n", ie->ie_caus_cause); + switch(ie->ie_caus_cause) { + case UNI_IE_CAUS_IECONTENT: + printf(" Flagged IEs: "); + for (i=0; ie->ie_caus_diagnostic[i]; i++) { + printf("0x%x ", ie->ie_caus_diagnostic[i]); + } + printf("\n"); + break; + case UNI_IE_CAUS_TIMER: + printf(" Timer ID: %c%c%c\n", + ie->ie_caus_diagnostic[0], + ie->ie_caus_diagnostic[1], + ie->ie_caus_diagnostic[2]); + break; + default: + printf(" Diag length: %d\n", + ie->ie_caus_diag_len); + printf(" Diagnostic: "); + for (i=0; i<ie->ie_caus_diag_len; i++) { + printf("0x%x ", ie->ie_caus_diagnostic[i]); + } + printf("\n"); + } +} + + +/* + * Print a connection identifier information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_cnid(ie) + struct ie_generic *ie; +{ + printf(" VP assoc sig: 0x%x\n", ie->ie_cnid_vp_sig); + printf(" Pref/excl: 0x%x\n", + ie->ie_cnid_pref_excl); + printf(" VPCI: %d\n", ie->ie_cnid_vpci); + printf(" VCI: %d\n", ie->ie_cnid_vci); +} + + +/* + * Print a quality of service parameter information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_qosp(ie) + struct ie_generic *ie; +{ + printf(" QoS fwd: 0x%x\n", + ie->ie_qosp_fwd_class); + printf(" QoS bkwd: 0x%x\n", + ie->ie_qosp_bkwd_class); +} + + +/* + * Print a broadband repeat indicator information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_brpi(ie) + struct ie_generic *ie; +{ + printf(" Indicator: 0x%x\n", ie->ie_brpi_ind); +} + + +/* + * Print a restart indicator information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_rsti(ie) + struct ie_generic *ie; +{ + printf(" Class: 0x%x\n", ie->ie_rsti_class); +} + + +/* + * Print a broadband locking shift information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_blsh(ie) + struct ie_generic *ie; +{ +} + + +/* + * Print a broadband non-locking shift information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_bnsh(ie) + struct ie_generic *ie; +{ +} + + +/* + * Print a broadband sending complete information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_bsdc(ie) + struct ie_generic *ie; +{ + printf(" Indication: 0x%x\n", ie->ie_bsdc_ind); +} + + +/* + * Print a transit net selection information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_trnt(ie) + struct ie_generic *ie; +{ +#ifdef NOTDEF + struct ie_generic ie_trnt_hdr; + u_char ie_trnt_id_type; + u_char ie_trnt_id_plan; + Atm_addr ie_trnt_id; +#endif +} + + +/* + * Print an endpoint reference information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_eprf(ie) + struct ie_generic *ie; +{ + printf(" Ref type: 0x%x\n", + ie->ie_eprf_type); + printf(" Endpt ref: 0x%x\n", + ie->ie_eprf_id); +} + + +/* + * Print an endpoint state information element + * + * Arguments: + * ie pointer to the IE to print + * + * Returns: + * None + * + */ +static void +usp_print_ie_epst(ie) + struct ie_generic *ie; +{ + printf(" Endpt state: %d\n", + ie->ie_epst_state); +} diff --git a/sys/netatm/uni/unisig_print.h b/sys/netatm/uni/unisig_print.h new file mode 100644 index 0000000..5e906c8 --- /dev/null +++ b/sys/netatm/uni/unisig_print.h @@ -0,0 +1,47 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: unisig_print.h,v 1.2 1997/05/06 22:22:27 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Protocol control blocks + * + */ + +#ifndef _UNISIG_PRINT_H +#define _UNISIG_PRINT_H + +/* + * Message direction for print routine + */ +#define UNISIG_MSG_IN 1 +#define UNISIG_MSG_OUT 2 + +#endif /* _UNISIG_PRINT_H */ diff --git a/sys/netatm/uni/unisig_proto.c b/sys/netatm/uni/unisig_proto.c new file mode 100644 index 0000000..914e76d --- /dev/null +++ b/sys/netatm/uni/unisig_proto.c @@ -0,0 +1,324 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: unisig_proto.c,v 1.9 1998/08/26 23:29:23 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Protocol processing module. + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_proto.c,v 1.9 1998/08/26 23:29:23 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/unisig.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/unisig_msg.h> +#include <netatm/uni/unisig_mbuf.h> + + +/* + * Process a UNISIG timeout + * + * Called when a previously scheduled protocol instance control block + * timer expires. This routine passes a timeout event to the UNISIG + * signalling manager state machine. + * + * Called at splnet. + * + * Arguments: + * tip pointer to UNISIG timer control block + * + * Returns: + * none + * + */ +void +unisig_timer(tip) + struct atm_time *tip; +{ + struct unisig *usp; + + /* + * Back-off to UNISIG control block + */ + usp = (struct unisig *) + ((caddr_t)tip - (int)(&((struct unisig *)0)->us_time)); + + ATM_DEBUG2("unisig_timer: usp=0x%x,state=%d\n", + (int)usp, usp->us_state); + + /* + * Pass the timeout to the signalling manager state machine + */ + (void) unisig_sigmgr_state(usp, + UNISIG_SIGMGR_TIMEOUT, + (KBuffer *) 0); +} + + +/* + * Process a UNISIG VCC timeout + * + * Called when a previously scheduled UNISIG VCCB timer expires. + * Processing will based on the current VCC state. + * + * Called at splnet. + * + * Arguments: + * tip pointer to vccb timer control block + * + * Returns: + * none + * + */ +void +unisig_vctimer(tip) + struct atm_time *tip; +{ + struct unisig *usp; + struct unisig_vccb *uvp; + + /* + * Get VCCB and UNISIG control block addresses + */ + uvp = (struct unisig_vccb *) ((caddr_t)tip - + (int)(&((struct vccb *)0)->vc_time)); + usp = (struct unisig *)uvp->uv_pif->pif_siginst; + + ATM_DEBUG3("unisig_vctimer: uvp=0x%x, sstate=%d, ustate=%d\n", + (int)uvp, uvp->uv_sstate, uvp->uv_ustate); + + /* + * Hand the timeout to the VC finite state machine + */ + if (uvp->uv_ustate == VCCU_ABORT) { + /* + * If we're aborting, this is an ABORT call + */ + (void) unisig_vc_state(usp, uvp, UNI_VC_ABORT_CALL, + (struct unisig_msg *) 0); + } else { + /* + * If we're not aborting, it's a timeout + */ + (void) unisig_vc_state(usp, uvp, UNI_VC_TIMEOUT, + (struct unisig_msg *) 0); + } +} + + +/* + * UNISIG SAAL Control Handler + * + * This is the module which receives data on the UNISIG signalling + * channel. Processing is based on the indication received from the + * SSCF and the protocol state. + * + * Arguments: + * cmd command code + * tok session token (pointer to UNISIG protocol control block) + * a1 argument 1 + * + * Returns: + * none + * + */ +void +unisig_saal_ctl(cmd, tok, a1) + int cmd; + void *tok; + void *a1; +{ + struct unisig *usp = tok; + + ATM_DEBUG4("unisig_upper: usp=0x%x,state=%d,cmd=%d,a1=0x%x,\n", + (u_long)usp, usp->us_state, cmd, (u_long)a1); + + /* + * Process command + */ + switch (cmd) { + + case SSCF_UNI_ESTABLISH_IND: + (void) unisig_sigmgr_state(usp, + UNISIG_SIGMGR_SSCF_EST_IND, + (KBuffer *) 0); + break; + + case SSCF_UNI_ESTABLISH_CNF: + (void) unisig_sigmgr_state(usp, + UNISIG_SIGMGR_SSCF_EST_CNF, + (KBuffer *) 0); + break; + + case SSCF_UNI_RELEASE_IND: + (void) unisig_sigmgr_state(usp, + UNISIG_SIGMGR_SSCF_RLS_IND, + (KBuffer *) 0); + break; + + case SSCF_UNI_RELEASE_CNF: + (void) unisig_sigmgr_state(usp, + UNISIG_SIGMGR_SSCF_RLS_CNF, + (KBuffer *) 0); + break; + + default: + log(LOG_ERR, + "unisig: unknown SAAL cmd: usp=0x%x, state=%d, cmd=%d\n", + (int)usp, usp->us_state, cmd); + } +} + + +/* + * UNISIG SAAL Data Handler + * + * This is the module which receives data on the UNISIG signalling + * channel. Processing is based on the protocol state. + * + * Arguments: + * tok session token (pointer to UNISIG protocol control block) + * m pointer to data + * + * Returns: + * none + * + */ +void +unisig_saal_data(tok, m) + void *tok; + KBuffer *m; +{ + struct unisig *usp = tok; + + ATM_DEBUG3("unisig_saal_data: usp=0x%x,state=%d,m=0x%x,\n", + (int)usp, usp->us_state, m); + + /* + * Pass data to signalling manager state machine + */ + (void) unisig_sigmgr_state(usp, + UNISIG_SIGMGR_SSCF_DATA_IND, + m); +} + + +/* + * Get Connection's Application/Owner Name + * + * Arguments: + * tok UNI signalling connection token (pointer to protocol instance) + * + * Returns: + * addr pointer to string containing our name + * + */ +caddr_t +unisig_getname(tok) + void *tok; +{ + struct unisig *usp = tok; + + if (usp->us_proto == ATM_SIG_UNI30) + return ("UNI3.0"); + else if (usp->us_proto == ATM_SIG_UNI31) + return ("UNI3.1"); + else if (usp->us_proto == ATM_SIG_UNI40) + return ("UNI4.0"); + else + return ("UNI"); +} + + +/* + * Process a VCC connection notification + * + * Should never be called. + * + * Arguments: + * tok user's connection token (unisig protocol block) + * + * Returns: + * none + * + */ +void +unisig_connected(tok) + void *tok; +{ + struct unisig *usp = tok; + + ATM_DEBUG2("unisig_connected: usp=0x%x,state=%d\n", + (u_long)usp, usp->us_state); + + /* + * Connected routine shouldn't ever get called for a PVC + */ + log(LOG_ERR, "unisig: connected notification, usp=0x%x\n", + (u_long)usp); +} + + +/* + * Process a VCC closed notification + * + * Called when UNISIG signalling channel is closed. + * + * Arguments: + * tok user's connection token (unisig protocol block) + * cp pointer to cause structure + * + * Returns: + * none + * + */ +void +unisig_cleared(tok, cp) + void *tok; + struct t_atm_cause *cp; +{ + struct unisig *usp = tok; + + ATM_DEBUG3("unisig_cleared: usp=0x%x, state=%d, cause=%d\n", + (u_long)usp, usp->us_state, cp->cause_value); + + /* + * VCC has been closed. Notify the signalling + * manager state machine. + */ + (void) unisig_sigmgr_state(usp, + UNISIG_SIGMGR_CALL_CLEARED, + (KBuffer *) 0); +} diff --git a/sys/netatm/uni/unisig_sigmgr_state.c b/sys/netatm/uni/unisig_sigmgr_state.c new file mode 100644 index 0000000..2fbbfca --- /dev/null +++ b/sys/netatm/uni/unisig_sigmgr_state.c @@ -0,0 +1,860 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: unisig_sigmgr_state.c,v 1.10 1998/08/26 23:29:24 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Signalling manager finite state machine + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_sigmgr_state.c,v 1.10 1998/08/26 23:29:24 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/uni.h> +#include <netatm/uni/unisig.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/unisig_msg.h> +#include <netatm/uni/unisig_mbuf.h> +#include <netatm/uni/unisig_decode.h> + +#include <netatm/uni/sscf_uni.h> + + +/* + * Local functions + */ +static int unisig_sigmgr_invalid __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act01 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act02 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act03 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act04 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act05 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act06 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act07 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act08 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act09 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act10 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act11 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act12 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act13 __P((struct unisig *, KBuffer *)); +static int unisig_sigmgr_act14 __P((struct unisig *, KBuffer *)); + + +/* + * State table. + */ +static int sigmgr_state_table[10][7] = { + /* 0 1 2 3 4 5 */ + { 1, 0, 0, 0, 0 }, /* 0 - Time out */ + { 0, 0, 3, 5, 0 }, /* 1 - SSCF estab ind */ + { 0, 0, 3, 5, 0 }, /* 2 - SSCF estab cnf */ + { 0, 0, 4, 6, 0 }, /* 3 - SSCF release ind */ + { 0, 0, 0, 6, 0 }, /* 4 - SSCF release cnf */ + { 0, 0, 0, 7, 0 }, /* 5 - SSCF data ind */ + { 0, 0, 2, 2, 0 }, /* 6 - SSCF unit data ind */ + { 0, 0, 8, 8, 8 }, /* 7 - Call cleared */ + { 14, 14, 14, 14, 0 }, /* 8 - Detach */ + { 13, 13, 0, 0, 0 } /* 9 - Address set */ +}; + +/* + * Action vector + */ +#define MAX_ACTION 15 +static int (*unisig_sigmgr_act_vec[MAX_ACTION]) + __P((struct unisig *, KBuffer *)) = { + unisig_sigmgr_invalid, + unisig_sigmgr_act01, + unisig_sigmgr_act02, + unisig_sigmgr_act03, + unisig_sigmgr_act04, + unisig_sigmgr_act05, + unisig_sigmgr_act06, + unisig_sigmgr_act07, + unisig_sigmgr_act08, + unisig_sigmgr_act09, + unisig_sigmgr_act10, + unisig_sigmgr_act11, + unisig_sigmgr_act12, + unisig_sigmgr_act13, + unisig_sigmgr_act14 +}; + + +/* + * ATM endpoint for UNI signalling channel + */ +static Atm_endpoint unisig_endpt = { + NULL, /* ep_next */ + ENDPT_UNI_SIG, /* ep_id */ + NULL, /* ep_ioctl */ + unisig_getname, /* ep_getname */ + unisig_connected, /* ep_connected */ + unisig_cleared, /* ep_cleared */ + NULL, /* ep_incoming */ + NULL, /* ep_addparty */ + NULL, /* ep_dropparty */ + NULL, /* ep_cpcs_ctl */ + NULL, /* ep_cpcs_data */ + unisig_saal_ctl, /* ep_saal_ctl */ + unisig_saal_data, /* ep_saal_data */ + NULL, /* ep_sscop_ctl */ + NULL /* ep_sscop_data */ +}; + + +/* + * ATM connection attributes for UNI signalling channel + */ +static Atm_attributes unisig_attr = { + NULL, /* nif */ + CMAPI_SAAL, /* api */ + UNI_VERS_3_0, /* api_init */ + 0, /* headin */ + 0, /* headout */ + { /* aal */ + T_ATM_PRESENT, /* aal.tag */ + ATM_AAL5 /* aal.aal_type */ + }, + { /* traffic */ + T_ATM_PRESENT, /* traffic.tag */ + { /* traffic.v */ + { /* traffic.v.forward */ + T_ATM_ABSENT, /* PCR_high */ + 0, /* PCR_all */ + T_ATM_ABSENT, /* SCR_high */ + T_ATM_ABSENT, /* SCR_all */ + T_ATM_ABSENT, /* MBS_high */ + T_ATM_ABSENT, /* MBS_all */ + T_NO, /* tagging */ + }, + { /* traffic.v.backward */ + T_ATM_ABSENT, /* PCR_high */ + 0, /* PCR_all */ + T_ATM_ABSENT, /* SCR_high */ + T_ATM_ABSENT, /* SCR_all */ + T_ATM_ABSENT, /* MBS_high */ + T_ATM_ABSENT, /* MBS_all */ + T_NO, /* tagging */ + }, + T_YES, /* best_effort */ + } + }, + { /* bearer */ + T_ATM_PRESENT, /* bearer.tag */ + { /* bearer.v */ + T_ATM_CLASS_X, /* class */ + T_ATM_NULL, /* traffic_type */ + T_ATM_NO_END_TO_END, /* timing_req */ + T_NO, /* clipping */ + T_ATM_1_TO_1, /* conn_conf */ + } + }, + { /* bhli */ + T_ATM_ABSENT, /* bhli.tag */ + }, + { /* blli */ + T_ATM_ABSENT, /* blli.tag_l2 */ + T_ATM_ABSENT, /* blli.tag_l3 */ + }, + { /* llc */ + T_ATM_ABSENT, /* llc.tag */ + }, + { /* called */ + T_ATM_PRESENT, /* called.tag */ + }, + { /* calling */ + T_ATM_ABSENT, /* calling.tag */ + }, + { /* qos */ + T_ATM_PRESENT, /* qos.tag */ + { /* qos.v */ + T_ATM_NETWORK_CODING, /* coding_standard */ + { /* qos.v.forward */ + T_ATM_QOS_CLASS_0, /* class */ + }, + { /* qos.v.backward */ + T_ATM_QOS_CLASS_0, /* class */ + } + } + }, + { /* transit */ + T_ATM_ABSENT, /* transit.tag */ + }, + { /* cause */ + T_ATM_ABSENT, /* cause.tag */ + } +}; + + +/* + * Finite state machine for the UNISIG signalling manager + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * event indication of the event to be processed + * m pointer to a buffer with a message (optional) + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +unisig_sigmgr_state(usp, event, m) + struct unisig *usp; + int event; + KBuffer *m; +{ + int action, err = 0; + + /* + * Cancel any signalling manager timer + */ + UNISIG_CANCEL(usp); + + /* + * Select an action based on the incoming event and + * the signalling manager's state + */ + action = sigmgr_state_table[event][usp->us_state]; + ATM_DEBUG4("unisig_sigmgr_state: usp=0x%x, state=%d, event=%d, action=%d\n", + (u_int) usp, usp->us_state, event, action); + if (action >= MAX_ACTION || action < 0) { + panic("unisig_sigmgr_state: invalid action\n"); + } + + /* + * Perform the requested action + */ + err = unisig_sigmgr_act_vec[action](usp, m); + + return(err); +} + + +/* + * Signalling manager state machine action 0 + * + * Invalid action + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_invalid(usp, m) + struct unisig *usp; + KBuffer *m; +{ + log(LOG_ERR, "unisig_sigmgr_state: unexpected action\n"); + if (m) + KB_FREEALL(m); + return(0); +} + + +/* + * Signalling manager state machine action 1 + * + * The kickoff timer has expired at attach time; go to + * UNISIG_ADDR_WAIT state. + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act01(usp, m) + struct unisig *usp; + KBuffer *m; +{ + /* + * Set the new state + */ + usp->us_state = UNISIG_ADDR_WAIT; + + return(0); +} + + +/* + * Signalling manager state machine action 2 + * + * Ignore the event + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act02(usp, m) + struct unisig *usp; + KBuffer *m; +{ + /* + * Ignore event, discard message if present + */ + if (m) + KB_FREEALL(m); + + return(0); +} + + +/* + * Signalling manager state machine action 3 + * + * SSCF session on signalling channel has come up + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act03(usp, m) + struct unisig *usp; + KBuffer *m; +{ + struct unisig_vccb *uvp, *vnext; + + /* + * Log the activation + */ + log(LOG_INFO, "unisig: signalling channel active\n"); + + /* + * Go to ACTIVE state + */ + usp->us_state = UNISIG_ACTIVE; + + /* + * Notify the VC state machine that the channel is up + */ + for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); + uvp; uvp = vnext) { + vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem); + (void) unisig_vc_state(usp, uvp, UNI_VC_SAAL_ESTAB, + (struct unisig_msg *) 0); + } + + return(0); +} + + +/* + * Signalling manager state machine action 4 + * + * A SSCF release indication was received. Try to establish an + * SSCF session on the signalling PVC. + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act04(usp, m) + struct unisig *usp; + KBuffer *m; +{ + int err; + + /* + * Try to establish an SSCF session. + */ + err = atm_cm_saal_ctl(SSCF_UNI_ESTABLISH_REQ, + usp->us_conn, + (void *)0); + if (err) + panic("unisig_sigmgr_act04: SSCF_UNI_ESTABLISH_REQ"); + + return(0); +} + + +/* + * Signalling manager state machine action 5 + * + * SSCF session on signalling channel has been reset + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act05(usp, m) + struct unisig *usp; + KBuffer *m; +{ + struct unisig_vccb *uvp, *vnext; + + /* + * Log the reset + */ + log(LOG_INFO, "unisig: signalling channel reset\n"); + + /* + * Notify the VC state machine of the reset + */ + for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); + uvp; uvp = vnext) { + vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem); + (void) unisig_vc_state(usp, uvp, UNI_VC_SAAL_ESTAB, + (struct unisig_msg *) 0); + } + + return(0); +} + + +/* + * Signalling manager state machine action 6 + * + * SSCF session on signalling channel has been lost + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act06(usp, m) + struct unisig *usp; + KBuffer *m; +{ + struct unisig_vccb *uvp, *vnext; + + /* + * Log the fact that the session has been lost + */ + log(LOG_INFO, "unisig: signalling channel SSCF session lost\n"); + + /* + * Notify the VC state machine of the loss + */ + for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); + uvp; uvp = vnext) { + vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem); + (void) unisig_vc_state(usp, uvp, UNI_VC_SAAL_FAIL, + (struct unisig_msg *) 0); + } + + /* + * Try to restart the SSCF session + */ + (void) unisig_sigmgr_act04(usp, (KBuffer *) 0); + + /* + * Go to INIT state + */ + usp->us_state = UNISIG_INIT; + + return(0); +} + + +/* + * Signalling manager state machine action 7 + * + * A Q.2931 signalling message has been received + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act07(usp, m) + struct unisig *usp; + KBuffer *m; +{ + int err; + + /* + * Pass the Q.2931 signalling message on + * to the VC state machine + */ + err = unisig_rcv_msg(usp, m); + + return(err); +} + + +/* + * Signalling manager state machine action 8 + * + * Process a CALL_CLOSED event for the signalling PVC + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act08(usp, m) + struct unisig *usp; + KBuffer *m; +{ + + /* + * Signalling manager is now incommunicado + */ + if (usp->us_state != UNISIG_DETACH) { + /* + * Log an error and set the state to NULL if + * we're not detaching + */ + log(LOG_ERR, "unisig: signalling channel closed\n"); + usp->us_state = UNISIG_NULL; + } + usp->us_conn = 0; + + return(0); +} + + +/* + * Signalling manager state machine action 9 + * + * Not used + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act09(usp, m) + struct unisig *usp; + KBuffer *m; +{ + log(LOG_ERR, "unisig_sigmgr_act09: unexpected action\n"); + if (m) + KB_FREEALL(m); + return (0); +} + + +/* + * Signalling manager state machine action 10 + * + * Not used + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act10(usp, m) + struct unisig *usp; + KBuffer *m; +{ + return(0); +} + + +/* + * Signalling manager state machine action 11 + * + * Not used + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act11(usp, m) + struct unisig *usp; + KBuffer *m; +{ + log(LOG_ERR, "unisig_sigmgr_act11: unexpected action\n"); + if (m) + KB_FREEALL(m); + return(0); +} + + +/* + * Signalling manager state machine action 12 + * + * Not used + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act12(usp, m) + struct unisig *usp; + KBuffer *m; +{ + log(LOG_ERR, "unisig_sigmgr_act11: unexpected action\n"); + if (m) + KB_FREEALL(m); + return(0); +} + + +/* + * Signalling manager state machine action 13 + * + * NSAP prefix has been set + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act13(usp, m) + struct unisig *usp; + KBuffer *m; +{ + int err; + Atm_addr_pvc *pvcp; + + /* + * Set UNI signalling channel connection attributes + */ + if (usp->us_proto == ATM_SIG_UNI30) + unisig_attr.api_init = UNI_VERS_3_0; + else + unisig_attr.api_init = UNI_VERS_3_1; + + unisig_attr.nif = usp->us_pif->pif_nif; + + unisig_attr.aal.v.aal5.forward_max_SDU_size = ATM_NIF_MTU; + unisig_attr.aal.v.aal5.backward_max_SDU_size = ATM_NIF_MTU; + unisig_attr.aal.v.aal5.SSCS_type = T_ATM_SSCS_SSCOP_REL; + + unisig_attr.called.tag = T_ATM_PRESENT; + unisig_attr.called.addr.address_format = T_ATM_PVC_ADDR; + unisig_attr.called.addr.address_length = sizeof(Atm_addr_pvc); + pvcp = (Atm_addr_pvc *)unisig_attr.called.addr.address; + ATM_PVC_SET_VPI(pvcp, UNISIG_SIG_VPI); + ATM_PVC_SET_VCI(pvcp, UNISIG_SIG_VCI); + unisig_attr.called.subaddr.address_format = T_ATM_ABSENT; + unisig_attr.called.subaddr.address_length = 0; + + unisig_attr.traffic.v.forward.PCR_all_traffic = + usp->us_pif->pif_pcr; + unisig_attr.traffic.v.backward.PCR_all_traffic = + usp->us_pif->pif_pcr; + + /* + * Create UNISIG signalling channel + */ + err = atm_cm_connect(&unisig_endpt, usp, &unisig_attr, + &usp->us_conn); + if (err) { + return(err); + } + + /* + * Establish the SSCF session + */ + err = atm_cm_saal_ctl(SSCF_UNI_ESTABLISH_REQ, + usp->us_conn, + (void *)0); + if (err) + panic("unisig_sigmgr_act13: SSCF_UNI_ESTABLISH_REQ"); + + /* + * Set the new state + */ + usp->us_state = UNISIG_INIT; + + return(0); +} + + +/* + * Signalling manager state machine action 14 + * + * Process a detach event + * + * Arguments: + * usp pointer to the UNISIG protocol control block + * m buffer pointer (may be NULL) + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_sigmgr_act14(usp, m) + struct unisig *usp; + KBuffer *m; +{ + int err; + struct unisig_vccb *sig_vccb, *uvp, *vnext; + struct atm_pif *pip; + struct t_atm_cause cause; + + /* + * Locate the signalling channel's VCCB + */ + sig_vccb = (struct unisig_vccb *)0; + if (usp->us_conn && usp->us_conn->co_connvc) + sig_vccb = (struct unisig_vccb *) + usp->us_conn->co_connvc->cvc_vcc; + + /* + * Terminate all of our VCCs + */ + for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); + uvp; uvp = vnext) { + vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem); + + /* + * Don't close the signalling VCC yet + */ + if (uvp == sig_vccb) + continue; + + /* + * Close VCC and notify owner + */ + err = unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + } + + /* + * Set the signalling manager state + */ + usp->us_state = UNISIG_DETACH; + + /* + * Close the signalling channel + */ + if (usp->us_conn) { + cause.coding_standard = T_ATM_ITU_CODING; + cause.coding_standard = T_ATM_LOC_USER; + cause.coding_standard = T_ATM_CAUSE_UNSPECIFIED_NORMAL; + err = atm_cm_release(usp->us_conn, &cause); + if (err) + panic("unisig_sigmgr_act14: close failed\n"); + } + + /* + * Get rid of protocol instance if there are no VCCs queued + */ + pip = usp->us_pif; + if (Q_HEAD(usp->us_vccq, struct vccb) == NULL && + pip->pif_sigmgr) { + struct sigmgr *smp = pip->pif_sigmgr; + int s = splimp(); + + pip->pif_sigmgr = NULL; + pip->pif_siginst = NULL; + (void) splx(s); + + UNLINK((struct siginst *)usp, struct siginst, + smp->sm_prinst, si_next); + KM_FREE(usp, sizeof(struct unisig), M_DEVBUF); + } + + /* + * Otherwise, wait for protocol instance to be freed + * during unisig_free processing for the last queued VCC + */ + + return (0); +} diff --git a/sys/netatm/uni/unisig_subr.c b/sys/netatm/uni/unisig_subr.c new file mode 100644 index 0000000..f8dc067 --- /dev/null +++ b/sys/netatm/uni/unisig_subr.c @@ -0,0 +1,1276 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: unisig_subr.c,v 1.12 1998/08/26 23:29:24 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Subroutines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_subr.c,v 1.12 1998/08/26 23:29:24 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/unisig.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/unisig_msg.h> + + +/* + * External variables + */ +extern struct ie_aalp ie_aalp_absent; +extern struct ie_clrt ie_clrt_absent; +extern struct ie_bbcp ie_bbcp_absent; +extern struct ie_bhli ie_bhli_absent; +extern struct ie_blli ie_blli_absent; +extern struct ie_clst ie_clst_absent; +extern struct ie_cdad ie_cdad_absent; +extern struct ie_cdsa ie_cdsa_absent; +extern struct ie_cgad ie_cgad_absent; +extern struct ie_cgsa ie_cgsa_absent; +extern struct ie_caus ie_caus_absent; +extern struct ie_cnid ie_cnid_absent; +extern struct ie_qosp ie_qosp_absent; +extern struct ie_brpi ie_brpi_absent; +extern struct ie_rsti ie_rsti_absent; +extern struct ie_blsh ie_blsh_absent; +extern struct ie_bnsh ie_bnsh_absent; +extern struct ie_bsdc ie_bsdc_absent; +extern struct ie_trnt ie_trnt_absent; +extern struct ie_eprf ie_eprf_absent; +extern struct ie_epst ie_epst_absent; + + +/* + * Set a cause code in an ATM attribute block + * + * Arguments: + * aap pointer to attribute block + * cause cause code + * + * Returns: + * none + * + */ +void +unisig_set_cause_attr(aap, cause) + Atm_attributes *aap; + int cause; +{ + /* + * Set the fields in the attribute block + */ + aap->cause.tag = T_ATM_PRESENT; + aap->cause.v.coding_standard = T_ATM_ITU_CODING; + aap->cause.v.location = T_ATM_LOC_USER; + aap->cause.v.cause_value = cause; + KM_ZERO(aap->cause.v.diagnostics, + sizeof(aap->cause.v.diagnostics)); +} + + +/* + * Open a UNI VCC + * + * Called when a user wants to open a VC. This function will construct + * a VCCB and, if we are opening an SVC, call the Q.2931 VC state + * machine. The user will have to wait for a notify event to be sure + * the SVC is fully open. + * + * Must be called at splnet. + * + * Arguments: + * usp pointer to UNISIG protocol instance + * cvp pointer to connection parameters for the VCC + * + * Returns: + * 0 VCC creation successful + * errno VCC setup failed - reason indicated + * + */ +int +unisig_open_vcc(usp, cvp) + struct unisig *usp; + Atm_connvc *cvp; +{ + struct atm_pif *pip = usp->us_pif; + struct unisig_vccb *uvp; + Atm_addr_pvc *pvp; + int err, pvc; + + ATM_DEBUG2("unisig_open_vcc: usp=0x%x, cvp=0x%x\n", usp, cvp); + + /* + * Validate user parameters. AAL and encapsulation are + * checked by the connection manager + */ + + /* + * Check called party address(es) + */ + if(cvp->cvc_attr.called.tag != T_ATM_PRESENT || + cvp->cvc_attr.called.addr.address_format == + T_ATM_ABSENT) { + return(EINVAL); + } + switch (cvp->cvc_attr.called.addr.address_format) { + case T_ATM_PVC_ADDR: + /* + * Make sure VPI/VCI is valid + */ + pvc = 1; + pvp = (Atm_addr_pvc *)cvp->cvc_attr.called.addr.address; + if ((ATM_PVC_GET_VPI(pvp) > pip->pif_maxvpi) || + (ATM_PVC_GET_VCI(pvp) == 0) || + (ATM_PVC_GET_VCI(pvp) > pip->pif_maxvci)) { + return(ERANGE); + } + + /* + * Make sure VPI/VCI is not already in use + */ + if (unisig_find_vpvc(usp, + ATM_PVC_GET_VPI(pvp), + ATM_PVC_GET_VCI(pvp), 0)) { + return(EEXIST); + } + ATM_DEBUG2("unisig_open_vcc: VPI.VCI=%d.%d\n", + ATM_PVC_GET_VPI(pvp), + ATM_PVC_GET_VCI(pvp)); + break; + + case T_ATM_ENDSYS_ADDR: + /* + * Check signalling state + */ + pvc = 0; + pvp = NULL; + if (usp->us_state != UNISIG_ACTIVE) { + return(ENETDOWN); + } + + /* + * Make sure there's no subaddress + */ + if (cvp->cvc_attr.called.subaddr.address_format != + T_ATM_ABSENT) { + return(EINVAL); + } + break; + + case T_ATM_E164_ADDR: + /* + * Check signalling state + */ + pvc = 0; + pvp = NULL; + if (usp->us_state != UNISIG_ACTIVE) { + return(ENETDOWN); + } + + /* + * Check destination address format + */ + if (cvp->cvc_attr.called.subaddr.address_format != + T_ATM_ENDSYS_ADDR && + cvp->cvc_attr.called.subaddr.address_format != + T_ATM_ABSENT) { + return(EINVAL); + } + break; + + default: + return(EPROTONOSUPPORT); + } + + /* + * Check that this is for the same interface UNISIG uses + */ + if (!cvp->cvc_attr.nif || + cvp->cvc_attr.nif->nif_pif != usp->us_pif) { + return(EINVAL); + } + + /* + * Allocate control block for VCC + */ + uvp = (struct unisig_vccb *)atm_allocate(&unisig_vcpool); + if (uvp == NULL) { + return(ENOMEM); + } + + /* + * Fill in VCCB + */ + if (pvc) { + uvp->uv_type = VCC_PVC | VCC_IN | VCC_OUT; + uvp->uv_vpi = ATM_PVC_GET_VPI(pvp); + uvp->uv_vci = ATM_PVC_GET_VCI(pvp); + uvp->uv_sstate = (usp->us_state == UNISIG_ACTIVE ? + UNI_PVC_ACTIVE : UNI_PVC_ACT_DOWN); + uvp->uv_ustate = VCCU_OPEN; + } else { + uvp->uv_type = VCC_SVC | VCC_IN | VCC_OUT; + uvp->uv_sstate = UNI_NULL; + uvp->uv_ustate = VCCU_POPEN; + } + uvp->uv_proto = usp->us_pif->pif_sigmgr->sm_proto; + uvp->uv_pif = usp->us_pif; + uvp->uv_nif = cvp->cvc_attr.nif; + uvp->uv_connvc = cvp; + uvp->uv_tstamp = time_second; + + /* + * Put VCCB on UNISIG queue + */ + ENQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq); + + /* + * Call the VC state machine if this is an SVC + */ + if (!pvc) { + err = unisig_vc_state(usp, uvp, UNI_VC_SETUP_CALL, + (struct unisig_msg *) 0); + if (err) { + /* + * On error, delete the VCCB + */ + DEQUEUE(uvp, struct unisig_vccb, uv_sigelem, + usp->us_vccq); + atm_free((caddr_t)uvp); + return(err); + } + } + + /* + * Link VCCB to VCC connection block + */ + cvp->cvc_vcc = (struct vccb *) uvp; + + return(0); +} + + +/* + * Close a UNISIG VCC + * + * Called when a user wants to close a VCC. This function will clean + * up the VCCB and, for an SVC, send a close request. + * + * Must be called at splnet. + * + * Arguments: + * usp pointer to UNISIG protocol instance + * uvp pointer to VCCB for the VCC to be closed + * + * Returns: + * 0 VCC is now closed + * errno error encountered + */ +int +unisig_close_vcc(usp, uvp) + struct unisig *usp; + struct unisig_vccb *uvp; +{ + int err = 0; + + ATM_DEBUG2("unisig_close_vcc: uvp=0x%x, state=%d\n", uvp, + uvp->uv_sstate); + + /* + * Check that this is for the same interface UNISIG uses + */ + if (uvp->uv_pif != usp->us_pif) { + return (EINVAL); + } + + /* + * Mark the close time. + */ + uvp->uv_tstamp = time_second; + + /* + * Process based on the connection type + */ + if (uvp->uv_type & VCC_PVC) { + uvp->uv_sstate = UNI_FREE; + uvp->uv_ustate = VCCU_CLOSED; + } else if (uvp->uv_type & VCC_SVC) { + /* + * Call the VC state machine + */ + uvp->uv_ustate = VCCU_CLOSED; + err = unisig_vc_state(usp, uvp, UNI_VC_RELEASE_CALL, + (struct unisig_msg *) 0); + } + + /* + * Wait for user to free resources + */ + return(err); +} + + +/* + * Clear a UNISIG VCC + * + * Called to internally clear a VCC. No external protocol is + * initiated, the VCC is just closed and the owner is notified. + * + * Must be called at splnet. + * + * Arguments: + * usp pointer to UNISIG protocol instance + * uvp pointer to VCCB for the VCC to be closed + * cause cause code giving the reason for the close + * + * Returns: + * 0 VCC is closed + * errno error encountered + */ +int +unisig_clear_vcc(usp, uvp, cause) + struct unisig *usp; + struct unisig_vccb *uvp; + int cause; +{ + u_char outstate; + + ATM_DEBUG3("unisig_clear_vcc: uvp=0x%x, state=%d, cause=%d\n", + (int)uvp, uvp->uv_sstate, cause); + + /* + * Check that this is for the same interface UNISIG uses + */ + if (uvp->uv_pif != usp->us_pif) { + return (EINVAL); + } + + /* + * Kill any possible timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Mark the close time. + */ + uvp->uv_tstamp = time_second; + + /* + * Close the VCC and notify the user + */ + outstate = uvp->uv_sstate; + uvp->uv_sstate = UNI_FREE; + uvp->uv_ustate = VCCU_CLOSED; + if (outstate == UNI_ACTIVE || + outstate == UNI_CALL_INITIATED || + outstate == UNI_CALL_OUT_PROC || + outstate == UNI_CONNECT_REQUEST || + outstate == UNI_RELEASE_REQUEST || + outstate == UNI_RELEASE_IND || + outstate == UNI_SSCF_RECOV || + outstate == UNI_PVC_ACT_DOWN || + outstate == UNI_PVC_ACTIVE) { + unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr, cause); + atm_cm_cleared(uvp->uv_connvc); + } + + /* + * Wait for user to free resources + */ + return(0); +} + + +#ifdef NOTDEF +/* + * Reset the switch state + * + * Arguments: + * usp pointer to UNISIG protocol instance + * + * Returns: + * none + * + */ +void +unisig_switch_reset(usp, cause) + struct unisig *usp; + int cause; +{ + int s; + struct unisig_vccb *uvp, *vnext; + + ATM_DEBUG2("unisig_switch_reset: usp=0x%x, cause=%d\n", + usp, cause); + + /* + * Terminate all of our VCCs + */ + s = splnet(); + for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp; + uvp = vnext) { + vnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem); + + if (uvp->uv_type & VCC_SVC) { + /* + * Close the SVC and notify the owner + */ + (void)unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + } else if (uvp->uv_type & VCC_PVC) { + /* + * Notify PVC owner of the state change + */ + switch(cause) { + case UNI_DOWN: + uvp->uv_sstate = UNI_PVC_ACT_DOWN; + break; + case UNI_UP: + uvp->uv_sstate = UNI_PVC_ACTIVE; + break; + } + atm_cm_cleared(uvp->uv_connvc, cause); + } else { + log(LOG_ERR, "unisig: invalid VCC type: vccb=0x%x, type=%d\n", + uvp, uvp->uv_type); + } + } + (void) splx(s); +} +#endif + + +/* + * Copy connection parameters from UNI 3.0 message IEs into + * an attribute block + * + * Arguments: + * usp pointer to UNISIG protocol instance + * msg pointer to the SETUP message + * ap pointer to the attribute block + * + * Returns: + * none + * + */ +void +unisig_save_attrs(usp, msg, ap) + struct unisig *usp; + struct unisig_msg *msg; + Atm_attributes *ap; +{ + /* + * Sanity check + */ + if (!msg || !ap) + return; + + /* + * Save the AAL parameters (AAL 3/4 and AAL 5 only) + */ + if (msg->msg_ie_aalp) { + struct ie_generic *aalp = msg->msg_ie_aalp; + + switch(msg->msg_ie_aalp->ie_aalp_aal_type) { + case UNI_IE_AALP_AT_AAL3: + ap->aal.tag = T_ATM_PRESENT; + ap->aal.type = + msg->msg_ie_aalp->ie_aalp_aal_type; + ap->aal.v.aal4.forward_max_SDU_size = + msg->msg_ie_aalp->ie_aalp_4_fwd_max_sdu; + ap->aal.v.aal4.backward_max_SDU_size = + msg->msg_ie_aalp->ie_aalp_4_bkwd_max_sdu; + ap->aal.v.aal4.SSCS_type = + msg->msg_ie_aalp->ie_aalp_4_sscs_type; + if (aalp->ie_aalp_4_mid_range == T_ATM_ABSENT) { + ap->aal.v.aal4.mid_low = T_ATM_ABSENT; + ap->aal.v.aal4.mid_high = T_ATM_ABSENT; + } else { + if (usp->us_proto == ATM_SIG_UNI30) { + ap->aal.v.aal4.mid_low = 0; + ap->aal.v.aal4.mid_high = + aalp->ie_aalp_4_mid_range + & UNI_IE_AALP_A3_R_MASK; + } else { + ap->aal.v.aal4.mid_low = + (aalp->ie_aalp_4_mid_range >> + UNI_IE_AALP_A3_R_SHIFT) + & UNI_IE_AALP_A3_R_MASK; + ap->aal.v.aal4.mid_high = + aalp->ie_aalp_4_mid_range + & UNI_IE_AALP_A3_R_MASK; + } + } + break; + case UNI_IE_AALP_AT_AAL5: + ap->aal.tag = T_ATM_PRESENT; + ap->aal.type = + msg->msg_ie_aalp->ie_aalp_aal_type; + ap->aal.v.aal5.forward_max_SDU_size = + msg->msg_ie_aalp->ie_aalp_5_fwd_max_sdu; + ap->aal.v.aal5.backward_max_SDU_size = + msg->msg_ie_aalp->ie_aalp_5_bkwd_max_sdu; + ap->aal.v.aal5.SSCS_type = + msg->msg_ie_aalp->ie_aalp_5_sscs_type; + break; + } + } + + /* + * Save traffic descriptor attributes + */ + if (msg->msg_ie_clrt) { + ap->traffic.tag = T_ATM_PRESENT; + ap->traffic.v.forward.PCR_high_priority = + msg->msg_ie_clrt->ie_clrt_fwd_peak; + ap->traffic.v.forward.PCR_all_traffic = + msg->msg_ie_clrt->ie_clrt_fwd_peak_01; + ap->traffic.v.forward.SCR_high_priority = + msg->msg_ie_clrt->ie_clrt_fwd_sust; + ap->traffic.v.forward.SCR_all_traffic = + msg->msg_ie_clrt->ie_clrt_fwd_sust_01; + ap->traffic.v.forward.MBS_high_priority = + msg->msg_ie_clrt->ie_clrt_fwd_burst; + ap->traffic.v.forward.MBS_all_traffic = + msg->msg_ie_clrt->ie_clrt_fwd_burst_01; + ap->traffic.v.backward.PCR_high_priority = + msg->msg_ie_clrt->ie_clrt_bkwd_peak; + ap->traffic.v.backward.PCR_all_traffic = + msg->msg_ie_clrt->ie_clrt_bkwd_peak_01; + ap->traffic.v.backward.SCR_high_priority = + msg->msg_ie_clrt->ie_clrt_bkwd_sust; + ap->traffic.v.backward.SCR_all_traffic = + msg->msg_ie_clrt->ie_clrt_bkwd_sust_01; + ap->traffic.v.backward.MBS_high_priority = + msg->msg_ie_clrt->ie_clrt_bkwd_burst; + ap->traffic.v.backward.MBS_all_traffic = + msg->msg_ie_clrt->ie_clrt_bkwd_burst_01; + ap->traffic.v.best_effort = + msg->msg_ie_clrt->ie_clrt_best_effort; + if (msg->msg_ie_clrt->ie_clrt_tm_options == + T_ATM_ABSENT) { + ap->traffic.v.forward.tagging = T_NO; + ap->traffic.v.backward.tagging = T_NO; + } else { + ap->traffic.v.forward.tagging = + (msg->msg_ie_clrt->ie_clrt_tm_options & + UNI_IE_CLRT_TM_FWD_TAG) != 0; + ap->traffic.v.backward.tagging = + (msg->msg_ie_clrt->ie_clrt_tm_options & + UNI_IE_CLRT_TM_BKWD_TAG) != 0; + } + } + + /* + * Save broadband bearer attributes + */ + if (msg->msg_ie_bbcp) { + ap->bearer.tag = T_ATM_PRESENT; + ap->bearer.v.bearer_class = + msg->msg_ie_bbcp->ie_bbcp_bearer_class; + ap->bearer.v.traffic_type = + msg->msg_ie_bbcp->ie_bbcp_traffic_type; + ap->bearer.v.timing_requirements = + msg->msg_ie_bbcp->ie_bbcp_timing_req; + ap->bearer.v.clipping_susceptibility = + msg->msg_ie_bbcp->ie_bbcp_clipping; + ap->bearer.v.connection_configuration = + msg->msg_ie_bbcp->ie_bbcp_conn_config; + } + + /* + * Save broadband high layer attributes + */ + if (msg->msg_ie_bhli) { + ap->bhli.tag = T_ATM_PRESENT; + ap->bhli.v.ID_type = msg->msg_ie_bhli->ie_bhli_type; + switch(ap->bhli.v.ID_type) { + case T_ATM_ISO_APP_ID: + KM_COPY(msg->msg_ie_bhli->ie_bhli_info, + ap->bhli.v.ID.ISO_ID, + sizeof(ap->bhli.v.ID.ISO_ID)); + break; + case T_ATM_USER_APP_ID: + KM_COPY(msg->msg_ie_bhli->ie_bhli_info, + ap->bhli.v.ID.user_defined_ID, + sizeof(ap->bhli.v.ID.user_defined_ID)); + break; + case T_ATM_VENDOR_APP_ID: + KM_COPY(msg->msg_ie_bhli->ie_bhli_info, + ap->bhli.v.ID.vendor_ID.OUI, + sizeof(ap->bhli.v.ID.vendor_ID.OUI)); + KM_COPY(&msg->msg_ie_bhli->ie_bhli_info[sizeof(ap->bhli.v.ID.vendor_ID.OUI)-1], + ap->bhli.v.ID.vendor_ID.app_ID, + sizeof(ap->bhli.v.ID.vendor_ID.app_ID)); + break; + } + } + + /* + * Save Broadband low layer, user layer 2 and 3 attributes + */ + if (msg->msg_ie_blli) { + /* + * Layer 2 parameters + */ + switch(msg->msg_ie_blli->ie_blli_l2_id) { + case UNI_IE_BLLI_L2P_ISO1745: + case UNI_IE_BLLI_L2P_Q921: + case UNI_IE_BLLI_L2P_X25L: + case UNI_IE_BLLI_L2P_X25M: + case UNI_IE_BLLI_L2P_LAPB: + case UNI_IE_BLLI_L2P_HDLC1: + case UNI_IE_BLLI_L2P_HDLC2: + case UNI_IE_BLLI_L2P_HDLC3: + case UNI_IE_BLLI_L2P_LLC: + case UNI_IE_BLLI_L2P_X75: + case UNI_IE_BLLI_L2P_Q922: + case UNI_IE_BLLI_L2P_ISO7776: + ap->blli.tag_l2 = T_ATM_PRESENT; + ap->blli.v.layer_2_protocol.ID_type = + T_ATM_SIMPLE_ID; + ap->blli.v.layer_2_protocol.ID.simple_ID = + msg->msg_ie_blli->ie_blli_l2_id; + break; + case UNI_IE_BLLI_L2P_USER: + ap->blli.tag_l2 = T_ATM_PRESENT; + ap->blli.v.layer_2_protocol.ID_type = + T_ATM_USER_ID; + ap->blli.v.layer_2_protocol.ID.user_defined_ID = + msg->msg_ie_blli->ie_blli_l2_user_proto; + break; + default: + ap->blli.tag_l2 = T_ATM_ABSENT; + } + if (ap->blli.tag_l2 == T_ATM_PRESENT) { + ap->blli.v.layer_2_protocol.mode = + msg->msg_ie_blli->ie_blli_l2_mode; + ap->blli.v.layer_2_protocol.window_size = + msg->msg_ie_blli->ie_blli_l2_window; + } + + /* + * Layer 3 parameters + */ + switch(msg->msg_ie_blli->ie_blli_l3_id) { + case UNI_IE_BLLI_L3P_X25: + case UNI_IE_BLLI_L3P_ISO8208: + case UNI_IE_BLLI_L3P_ISO8878: + case UNI_IE_BLLI_L3P_ISO8473: + case UNI_IE_BLLI_L3P_T70: + ap->blli.tag_l3 = T_ATM_PRESENT; + ap->blli.v.layer_3_protocol.ID_type = + T_ATM_SIMPLE_ID; + ap->blli.v.layer_3_protocol.ID.simple_ID = + msg->msg_ie_blli->ie_blli_l3_id; + break; + case UNI_IE_BLLI_L3P_ISO9577: + ap->blli.tag_l3 = T_ATM_PRESENT; + ap->blli.v.layer_3_protocol.ID_type = + T_ATM_SIMPLE_ID; + ap->blli.v.layer_3_protocol.ID.simple_ID = + msg->msg_ie_blli->ie_blli_l3_id; + if (msg->msg_ie_blli->ie_blli_l3_ipi == + UNI_IE_BLLI_L3IPI_SNAP) { + KM_COPY(msg->msg_ie_blli->ie_blli_l3_oui, + ap->blli.v.layer_3_protocol.ID.SNAP_ID.OUI, + sizeof(ap->blli.v.layer_3_protocol.ID.SNAP_ID.OUI)); + KM_COPY(msg->msg_ie_blli->ie_blli_l3_pid, + ap->blli.v.layer_3_protocol.ID.SNAP_ID.PID, + sizeof(ap->blli.v.layer_3_protocol.ID.SNAP_ID.PID)); + } else { + ap->blli.v.layer_3_protocol.ID.IPI_ID = + msg->msg_ie_blli->ie_blli_l3_ipi; + } + break; + case UNI_IE_BLLI_L3P_USER: + ap->blli.tag_l3 = T_ATM_PRESENT; + ap->blli.v.layer_3_protocol.ID_type = + T_ATM_USER_ID; + ap->blli.v.layer_3_protocol.ID.user_defined_ID = + msg->msg_ie_blli->ie_blli_l3_user_proto; + break; + default: + ap->blli.tag_l3 = T_ATM_ABSENT; + } + if (ap->blli.tag_l3 == T_ATM_PRESENT) { + ap->blli.v.layer_3_protocol.mode = + msg->msg_ie_blli->ie_blli_l3_mode; + ap->blli.v.layer_3_protocol.packet_size = + msg->msg_ie_blli->ie_blli_l3_packet_size; + ap->blli.v.layer_3_protocol.window_size = + msg->msg_ie_blli->ie_blli_l3_window; + } + } + + /* + * Save the called party address and subaddress + */ + if (msg->msg_ie_cdad) { + ap->called.tag = T_ATM_PRESENT; + ATM_ADDR_COPY(&msg->msg_ie_cdad->ie_cdad_addr, + &ap->called.addr); + ap->called.subaddr.address_format = T_ATM_ABSENT; + ap->called.subaddr.address_length = 0; + } + if (msg->msg_ie_cdsa) { + ATM_ADDR_COPY(&msg->msg_ie_cdsa->ie_cdsa_addr, + &ap->called.subaddr); + } + + /* + * Save the calling party address and subaddress + */ + if (msg->msg_ie_cgad) { + ap->calling.tag = T_ATM_PRESENT; + ATM_ADDR_COPY(&msg->msg_ie_cgad->ie_cgad_addr, + &ap->calling.addr); + ap->calling.subaddr.address_format = T_ATM_ABSENT; + ap->calling.subaddr.address_length = 0; + } + + if (msg->msg_ie_cgsa) { + ATM_ADDR_COPY(&msg->msg_ie_cgsa->ie_cgsa_addr, + &ap->calling.subaddr); + } + + /* + * Save quality of service attributes + */ + if (msg->msg_ie_qosp) { + ap->qos.tag = T_ATM_PRESENT; + ap->qos.v.coding_standard = msg->msg_ie_qosp->ie_coding; + ap->qos.v.forward.qos_class = msg->msg_ie_qosp->ie_qosp_fwd_class; + ap->qos.v.forward.qos_class = + msg->msg_ie_qosp->ie_qosp_bkwd_class; + } + + /* + * Save transit network attributes + */ + if (msg->msg_ie_trnt) { + ap->transit.tag = T_ATM_PRESENT; + ap->transit.v.length = + MIN(msg->msg_ie_trnt->ie_trnt_id_len, + sizeof(ap->transit.v.network_id)); + KM_COPY(msg->msg_ie_trnt->ie_trnt_id, + ap->transit.v.network_id, + ap->transit.v.length); + } + + /* + * Save cause code + */ + if (msg->msg_ie_caus) { + ap->cause.tag = T_ATM_PRESENT; + ap->cause.v.coding_standard = + msg->msg_ie_caus->ie_coding; + ap->cause.v.location = + msg->msg_ie_caus->ie_caus_loc; + ap->cause.v.cause_value = + msg->msg_ie_caus->ie_caus_cause; + KM_ZERO(ap->cause.v.diagnostics, + sizeof(ap->cause.v.diagnostics)); +#ifdef NOTDEF + KM_COPY(msg->msg_ie_caus->ie_caus_diagnostic, + ap->transit.v.diagnostics, + MIN(sizeof(ap->transit.v.diagnostics), + msg->msg_ie_caus->ie_caus_diag_len)); +#endif + } +} + + +/* + * Copy connection parameters from an attribute block into + * UNI 3.0 message IEs + * + * Arguments: + * usp pointer to UNISIG protocol instance + * msg pointer to the SETUP message + * ap pointer to the attribute block + * + * Returns: + * 0 everything OK + * else error encountered + * + */ +int +unisig_set_attrs(usp, msg, ap) + struct unisig *usp; + struct unisig_msg *msg; + Atm_attributes *ap; +{ + int err = 0; + + /* + * Sanity check + */ + if (!msg || !ap) + return(EINVAL); + + /* + * Set the AAL parameters (AAL 3/4 and AAL 5 only) + */ + if (ap->aal.tag == T_ATM_PRESENT) { + if (!msg->msg_ie_aalp) { + msg->msg_ie_aalp = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_aalp == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_aalp_absent, + &msg->msg_ie_aalp->ie_u.ie_aalp, + sizeof(ie_aalp_absent)); + msg->msg_ie_aalp->ie_ident = UNI_IE_AALP; + msg->msg_ie_aalp->ie_aalp_aal_type = ap->aal.type; + switch(ap->aal.type) { + case ATM_AAL3_4: + msg->msg_ie_aalp->ie_aalp_4_fwd_max_sdu = + ap->aal.v.aal4.forward_max_SDU_size; + msg->msg_ie_aalp->ie_aalp_4_bkwd_max_sdu = + ap->aal.v.aal4.backward_max_SDU_size; + msg->msg_ie_aalp->ie_aalp_4_mode = UNI_IE_AALP_A5_M_MSG; + msg->msg_ie_aalp->ie_aalp_4_sscs_type = + ap->aal.v.aal4.SSCS_type; + if (ap->aal.v.aal4.mid_low == T_ATM_ABSENT) { + msg->msg_ie_aalp->ie_aalp_4_mid_range = + T_ATM_ABSENT; + } else { + if (usp->us_proto == ATM_SIG_UNI30) { + msg->msg_ie_aalp->ie_aalp_4_mid_range = + ap->aal.v.aal4.mid_high & + UNI_IE_AALP_A3_R_MASK; + } else { + msg->msg_ie_aalp->ie_aalp_4_mid_range = + ((ap->aal.v.aal4.mid_low & + UNI_IE_AALP_A3_R_MASK) + << UNI_IE_AALP_A3_R_SHIFT) + | + (ap->aal.v.aal4.mid_high & + UNI_IE_AALP_A3_R_MASK); + } + } + break; + case ATM_AAL5: + msg->msg_ie_aalp->ie_aalp_5_fwd_max_sdu = + ap->aal.v.aal5.forward_max_SDU_size; + msg->msg_ie_aalp->ie_aalp_5_bkwd_max_sdu = + ap->aal.v.aal5.backward_max_SDU_size; + msg->msg_ie_aalp->ie_aalp_5_mode = + UNI_IE_AALP_A5_M_MSG; + msg->msg_ie_aalp->ie_aalp_5_sscs_type = + ap->aal.v.aal5.SSCS_type; + break; + } + } + + /* + * Set traffic descriptor attributes + */ + if (ap->traffic.tag == T_ATM_PRESENT) { + if (!msg->msg_ie_clrt) { + msg->msg_ie_clrt = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_clrt == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_clrt_absent, + &msg->msg_ie_clrt->ie_u.ie_clrt, + sizeof(ie_clrt_absent)); + msg->msg_ie_clrt->ie_ident = UNI_IE_CLRT; + msg->msg_ie_clrt->ie_clrt_fwd_peak = + ap->traffic.v.forward.PCR_high_priority; + msg->msg_ie_clrt->ie_clrt_fwd_peak_01 = + ap->traffic.v.forward.PCR_all_traffic; + msg->msg_ie_clrt->ie_clrt_fwd_sust = + ap->traffic.v.forward.SCR_high_priority; + msg->msg_ie_clrt->ie_clrt_fwd_sust_01 = + ap->traffic.v.forward.SCR_all_traffic; + msg->msg_ie_clrt->ie_clrt_fwd_burst = + ap->traffic.v.forward.MBS_high_priority; + msg->msg_ie_clrt->ie_clrt_fwd_burst_01 = + ap->traffic.v.forward.MBS_all_traffic; + msg->msg_ie_clrt->ie_clrt_bkwd_peak = + ap->traffic.v.backward.PCR_high_priority; + msg->msg_ie_clrt->ie_clrt_bkwd_peak_01 = + ap->traffic.v.backward.PCR_all_traffic; + msg->msg_ie_clrt->ie_clrt_bkwd_sust = + ap->traffic.v.backward.SCR_high_priority; + msg->msg_ie_clrt->ie_clrt_bkwd_sust_01 = + ap->traffic.v.backward.SCR_all_traffic; + msg->msg_ie_clrt->ie_clrt_bkwd_burst = + ap->traffic.v.backward.MBS_high_priority; + msg->msg_ie_clrt->ie_clrt_bkwd_burst_01 = + ap->traffic.v.backward.MBS_all_traffic; + msg->msg_ie_clrt->ie_clrt_best_effort = + ap->traffic.v.best_effort; + msg->msg_ie_clrt->ie_clrt_tm_options = 0; + if (ap->traffic.v.forward.tagging) { + msg->msg_ie_clrt->ie_clrt_tm_options |= + UNI_IE_CLRT_TM_FWD_TAG; + } + if (ap->traffic.v.backward.tagging) { + msg->msg_ie_clrt->ie_clrt_tm_options |= + UNI_IE_CLRT_TM_BKWD_TAG; + } + if (msg->msg_ie_clrt->ie_clrt_tm_options == 0) { + msg->msg_ie_clrt->ie_clrt_tm_options = + T_ATM_ABSENT; + } + } + + /* + * Set broadband bearer attributes + */ + if (ap->bearer.tag == T_ATM_PRESENT) { + if (!msg->msg_ie_bbcp) { + msg->msg_ie_bbcp = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_bbcp == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_bbcp_absent, + &msg->msg_ie_bbcp->ie_u.ie_bbcp, + sizeof(ie_bbcp_absent)); + msg->msg_ie_bbcp->ie_ident = UNI_IE_BBCP; + msg->msg_ie_bbcp->ie_bbcp_bearer_class = + ap->bearer.v.bearer_class; + msg->msg_ie_bbcp->ie_bbcp_traffic_type = + ap->bearer.v.traffic_type; + msg->msg_ie_bbcp->ie_bbcp_timing_req = + ap->bearer.v.timing_requirements; + msg->msg_ie_bbcp->ie_bbcp_clipping = + ap->bearer.v.clipping_susceptibility; + msg->msg_ie_bbcp->ie_bbcp_conn_config = + ap->bearer.v.connection_configuration; + } + + /* + * Set broadband high layer attributes + */ + if (ap->bhli.tag == T_ATM_PRESENT) { + if (!msg->msg_ie_bhli) { + msg->msg_ie_bhli = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_bhli == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_bhli_absent, + &msg->msg_ie_bhli->ie_u.ie_bhli, + sizeof(ie_bhli_absent)); + msg->msg_ie_bhli->ie_ident = UNI_IE_BHLI; + msg->msg_ie_bhli->ie_bhli_type = ap->bhli.v.ID_type; + switch (ap->bhli.v.ID_type) { + case T_ATM_ISO_APP_ID: + KM_COPY(ap->bhli.v.ID.ISO_ID, + msg->msg_ie_bhli->ie_bhli_info, + sizeof(ap->bhli.v.ID.ISO_ID)); + break; + case T_ATM_USER_APP_ID: + KM_COPY(ap->bhli.v.ID.user_defined_ID, + msg->msg_ie_bhli->ie_bhli_info, + sizeof(ap->bhli.v.ID.user_defined_ID)); + break; + case T_ATM_VENDOR_APP_ID: + KM_COPY(ap->bhli.v.ID.vendor_ID.OUI, + msg->msg_ie_bhli->ie_bhli_info, + sizeof(ap->bhli.v.ID.vendor_ID.OUI)); + KM_COPY(ap->bhli.v.ID.vendor_ID.app_ID, + &msg->msg_ie_bhli->ie_bhli_info[sizeof(ap->bhli.v.ID.vendor_ID.OUI)-1], + sizeof(ap->bhli.v.ID.vendor_ID.app_ID)); + break; + } + } + + /* + * Set Broadband low layer, user layer 2 and 3 attributes + */ + if (ap->blli.tag_l2 == T_ATM_PRESENT || + ap->blli.tag_l3 == T_ATM_PRESENT) { + if (!msg->msg_ie_blli) { + msg->msg_ie_blli = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_blli == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_blli_absent, + &msg->msg_ie_blli->ie_u.ie_blli, + sizeof(ie_blli_absent)); + msg->msg_ie_blli->ie_ident = UNI_IE_BLLI; + + if (ap->blli.tag_l2 == T_ATM_PRESENT) { + switch(ap->blli.v.layer_2_protocol.ID_type) { + case T_ATM_SIMPLE_ID: + msg->msg_ie_blli->ie_blli_l2_id = + ap->blli.v.layer_2_protocol.ID.simple_ID; + break; + case T_ATM_USER_ID: + msg->msg_ie_blli->ie_blli_l2_user_proto = + ap->blli.v.layer_2_protocol.ID.user_defined_ID; + break; + } + if (ap->blli.v.layer_2_protocol.ID_type != + T_ATM_ABSENT) { + msg->msg_ie_blli->ie_blli_l2_mode = + ap->blli.v.layer_2_protocol.mode; + msg->msg_ie_blli->ie_blli_l2_window = + ap->blli.v.layer_2_protocol.window_size; + } + } + + if (ap->blli.tag_l3 == T_ATM_PRESENT) { + switch (ap->blli.v.layer_3_protocol.ID_type) { + case T_ATM_SIMPLE_ID: + msg->msg_ie_blli->ie_blli_l3_id = + ap->blli.v.layer_3_protocol.ID.simple_ID; + break; + + case T_ATM_IPI_ID: + msg->msg_ie_blli->ie_blli_l3_id = + UNI_IE_BLLI_L3P_ISO9577; + msg->msg_ie_blli->ie_blli_l3_ipi = + ap->blli.v.layer_3_protocol.ID.IPI_ID; + break; + + case T_ATM_SNAP_ID: + msg->msg_ie_blli->ie_blli_l3_id = + UNI_IE_BLLI_L3P_ISO9577; + msg->msg_ie_blli->ie_blli_l3_ipi = + UNI_IE_BLLI_L3IPI_SNAP; + KM_COPY(ap->blli.v.layer_3_protocol.ID.SNAP_ID.OUI, + msg->msg_ie_blli->ie_blli_l3_oui, + sizeof(msg->msg_ie_blli->ie_blli_l3_oui)); + KM_COPY(ap->blli.v.layer_3_protocol.ID.SNAP_ID.PID, + msg->msg_ie_blli->ie_blli_l3_pid, + sizeof(msg->msg_ie_blli->ie_blli_l3_pid)); + break; + + case T_ATM_USER_ID: + msg->msg_ie_blli->ie_blli_l3_id = + UNI_IE_BLLI_L3P_USER; + msg->msg_ie_blli->ie_blli_l3_user_proto = + ap->blli.v.layer_3_protocol.ID.user_defined_ID; + break; + } + if (ap->blli.v.layer_3_protocol.ID_type + != T_ATM_ABSENT) { + msg->msg_ie_blli->ie_blli_l3_mode = + ap->blli.v.layer_3_protocol.mode; + msg->msg_ie_blli->ie_blli_l3_packet_size = + ap->blli.v.layer_3_protocol.packet_size; + msg->msg_ie_blli->ie_blli_l3_window = + ap->blli.v.layer_3_protocol.window_size; + } + } + } + + /* + * Set the called party address and subaddress + */ + if (ap->called.tag == T_ATM_PRESENT) { + if (!msg->msg_ie_cdad) { + msg->msg_ie_cdad = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_cdad == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_cdad_absent, + &msg->msg_ie_cdad->ie_u.ie_cdad, + sizeof(ie_cdad_absent)); + msg->msg_ie_cdad->ie_ident = UNI_IE_CDAD; + ATM_ADDR_COPY(&ap->called.addr, + &msg->msg_ie_cdad->ie_cdad_addr); + + if (ap->called.subaddr.address_format != T_ATM_ABSENT) { + if (!msg->msg_ie_cdsa) { + msg->msg_ie_cdsa = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_cdsa == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_cdsa_absent, + &msg->msg_ie_cdsa->ie_u.ie_cdsa, + sizeof(ie_cdsa_absent)); + msg->msg_ie_cdsa->ie_ident = UNI_IE_CDSA; + ATM_ADDR_COPY(&ap->called.subaddr, + &msg->msg_ie_cdsa->ie_cdsa_addr); + } + } + + /* + * Set the calling party address and subaddress + */ + + if (ap->calling.tag == T_ATM_PRESENT) { + if (!msg->msg_ie_cgad) { + msg->msg_ie_cgad = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_cgad == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_cgad_absent, + &msg->msg_ie_cgad->ie_u.ie_cgad, + sizeof(ie_cgad_absent)); + msg->msg_ie_cgsa->ie_ident = UNI_IE_CGSA; + ATM_ADDR_COPY(&ap->calling.addr, + &msg->msg_ie_cgad->ie_cgad_addr); + + if (ap->calling.subaddr.address_format != + T_ATM_ABSENT) { + if (!msg->msg_ie_cgsa) { + msg->msg_ie_cgsa = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_cgsa == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_cgsa_absent, + &msg->msg_ie_cgsa->ie_u.ie_cgsa, + sizeof(ie_cgsa_absent)); + msg->msg_ie_cgsa->ie_ident = UNI_IE_CGSA; + ATM_ADDR_COPY(&ap->calling.subaddr, + &msg->msg_ie_cgsa->ie_cgsa_addr); + } + } + + /* + * Set quality of service attributes + */ + if (ap->qos.tag == T_ATM_PRESENT) { + if (!msg->msg_ie_qosp) { + msg->msg_ie_qosp = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_qosp == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_qosp_absent, + &msg->msg_ie_qosp->ie_u.ie_qosp, + sizeof(ie_qosp_absent)); + msg->msg_ie_qosp->ie_ident = UNI_IE_QOSP; + if (usp->us_proto == ATM_SIG_UNI30) + msg->msg_ie_qosp->ie_coding = UNI_IE_CODE_STD; + else if ((ap->qos.v.forward.qos_class == + T_ATM_QOS_CLASS_0) || + (ap->qos.v.backward.qos_class == + T_ATM_QOS_CLASS_0)) + msg->msg_ie_qosp->ie_coding = UNI_IE_CODE_CCITT; + else + msg->msg_ie_qosp->ie_coding = ap->qos.v.coding_standard; + msg->msg_ie_qosp->ie_qosp_fwd_class = + ap->qos.v.forward.qos_class; + msg->msg_ie_qosp->ie_qosp_bkwd_class = + ap->qos.v.backward.qos_class; + } + + /* + * Set transit network attributes + */ + if (ap->transit.tag == T_ATM_PRESENT && + ap->transit.v.length != 0) { + if (!msg->msg_ie_trnt) { + msg->msg_ie_trnt = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_trnt == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_trnt_absent, + &msg->msg_ie_trnt->ie_u.ie_trnt, + sizeof(ie_trnt_absent)); + msg->msg_ie_trnt->ie_ident = UNI_IE_TRNT; + msg->msg_ie_trnt->ie_trnt_id_type = + UNI_IE_TRNT_IDT_NATL; + msg->msg_ie_trnt->ie_trnt_id_plan = + UNI_IE_TRNT_IDP_CIC; + KM_COPY(ap->transit.v.network_id, + msg->msg_ie_trnt->ie_trnt_id, + ap->transit.v.length); + } + + /* + * Set cause code + */ + if (ap->cause.tag == T_ATM_PRESENT) { + if (!msg->msg_ie_caus) { + msg->msg_ie_caus = (struct ie_generic *) + atm_allocate(&unisig_iepool); + if (msg->msg_ie_caus == NULL) { + err = ENOMEM; + goto done; + } + } + KM_COPY(&ie_caus_absent, + &msg->msg_ie_caus->ie_u.ie_caus, + sizeof(ie_caus_absent)); + msg->msg_ie_caus->ie_ident = UNI_IE_CAUS; + msg->msg_ie_caus->ie_coding = + ap->cause.v.coding_standard; + msg->msg_ie_caus->ie_caus_loc = + ap->cause.v.location; + msg->msg_ie_caus->ie_caus_cause = + ap->cause.v.cause_value; + + /* + * Don't copy the diagnostics from the attribute + * block, as there's no way to tell how much of + * the diagnostic field is relevant + */ + msg->msg_ie_caus->ie_caus_diag_len = 0; + } + +done: + return(err); +} diff --git a/sys/netatm/uni/unisig_util.c b/sys/netatm/uni/unisig_util.c new file mode 100644 index 0000000..ec4fbd0 --- /dev/null +++ b/sys/netatm/uni/unisig_util.c @@ -0,0 +1,389 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: unisig_util.c,v 1.9 1998/08/26 23:29:24 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Protocol processing module + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_util.c,v 1.9 1998/08/26 23:29:24 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/unisig.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/unisig_msg.h> + + +/* + * Free a UNISIG signalling message + * + * Free the passed message and any IEs that are attached to it + * + * Arguments: + * msg pointer to UNISIG protocol instance + * + * Returns: + * none + * + */ +void +unisig_free_msg(msg) + struct unisig_msg *msg; +{ + int i; + struct ie_generic *ie, *ienxt; + + ATM_DEBUG1("unisig_free_msg: msg=0x%x\n", msg); + + /* + * First free all the IEs + */ + for (i=0; i<UNI_MSG_IE_CNT; i++) { + ie = msg->msg_ie_vec[i]; + while (ie) { + ienxt = ie->ie_next; + atm_free(ie); + ie = ienxt; + } + } + + /* + * Finally, free the message structure itself + */ + atm_free(msg); +} + + +/* + * Verify a VCCB + * + * Search UNISIG's VCCB queue to verify that a VCCB belongs to UNISIG. + * + * Arguments: + * usp pointer to UNISIG protocol instance + * svp pointer to a VCCB + * + * Returns: + * TRUE the VCCB belongs to UNISIG + * FALSE the VCCB doesn't belong to UNISIG + * + */ +int +unisig_verify_vccb(usp, uvp) + struct unisig *usp; + struct unisig_vccb *uvp; + +{ + struct unisig_vccb *utp, *uvnext; + + for (utp = Q_HEAD(usp->us_vccq, struct unisig_vccb); + utp; utp = uvnext){ + uvnext = Q_NEXT(utp, struct unisig_vccb, uv_sigelem); + if (uvp == utp) { + return(TRUE); + } + } + return(FALSE); +} + + +/* + * Find a connection + * + * Find a VCCB given the call reference + * + * Arguments: + * usp pointer to UNISIG protocol instance + * cref the call reference to search for + * + * Returns: + * 0 there is no such VCCB + * uvp the address of the VCCB + * + */ +struct unisig_vccb * +unisig_find_conn(usp, cref) + struct unisig *usp; + u_int cref; + +{ + struct unisig_vccb *uvp, *uvnext; + + for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp; + uvp = uvnext){ + uvnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem); + if (uvp->uv_call_ref == cref) + break; + } + return(uvp); +} + + +/* + * Find a VCCB + * + * Find a VCCB given the VPI and VCI. + * + * Arguments: + * usp pointer to UNISIG protocol instance + * vpi the VPI to search for + * vci the VCI to search for + * dir the direction of the VCC (VCC_IN, VCC_OUT, or both). + * If dir is set to zero, return the address of any VCCB + * with the given VPI/VCI, regardless of direction. + * + * Returns: + * 0 there is no such VCCB + * uvp the address of the VCCB + * + */ +struct unisig_vccb * +unisig_find_vpvc(usp, vpi, vci, dir) + struct unisig *usp; + int vpi, vci; + u_char dir; + +{ + struct unisig_vccb *uvp, *uvnext; + + for (uvp = Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp; + uvp = uvnext){ + uvnext = Q_NEXT(uvp, struct unisig_vccb, uv_sigelem); + if (uvp->uv_vpi == vpi && + uvp->uv_vci == vci && + (uvp->uv_type & dir) == dir) + break; + } + return(uvp); +} + + +/* + * Allocate a call reference value + * + * Arguments: + * usp pointer to UNISIG protocol instance + * + * Returns: + * 0 call reference not available + * cref the call reference value + * + */ +int +unisig_alloc_call_ref(usp) + struct unisig *usp; + +{ + int cref; + + /* + * Get the next call reference value + */ + cref = usp->us_cref; + + /* + * Make sure it hasn't got too large + */ + if (cref >= UNI_MSG_CALL_REF_DUMMY) { + /* XXX */ + log(LOG_ERR, "uni: call reference limit reached\n"); + return(0); + } + + /* + * Bump the call reference value + */ + usp->us_cref++; + + return(cref); +} + + +/* + * Print an ATM address + * + * Convert an ATM address into an ASCII string suitable for printing. + * + * Arguments: + * p pointer to an ATM address + * + * Returns: + * the address of a string with the ASCII representation of the + * address. This routine returns the address of a statically- + * allocated buffer, so if repeated calls to this routine are made, + * each call will destroy the result of the previous call. + * + */ +char * +unisig_addr_print(p) + Atm_addr *p; +{ + int i; + char *fp, *op, t_buff[16]; + u_char *cp; + static char strbuff[256]; + + static char nf_DCC[] = "0xX.XX.X.XXX.XX.XX.XX.XXXXXX.X"; + static char nf_ICD[] = "0xX.XX.X.XXX.XX.XX.XX.XXXXXX.X"; + static char nf_E164[] = "0xX.XXXXXXXX.XX.XX.XXXXXX.X"; + + union { + int w; + char c[4]; + } u1, u2; + + /* + * Clear the print buffer + */ + KM_ZERO(strbuff, sizeof(strbuff)); + + /* + * Select appropriate printing format + */ + switch(p->address_format) { + case T_ATM_ENDSYS_ADDR: + /* + * Select format by NSAP type + */ + switch(((Atm_addr_nsap *)p->address)->aan_afi) { + default: + case AFI_DCC: + fp = nf_DCC; + break; + case AFI_ICD: + fp = nf_ICD; + break; + case AFI_E164: + fp = nf_E164; + break; + } + + /* + * Loop through the format string, converting the NSAP + * to ASCII + */ + cp = (u_char *) p->address; + op = strbuff; + while (*fp) { + if (*fp == 'X') { + /* + * If format character is an 'X', put a + * two-digit hex representation of the + * NSAP byte in the output buffer + */ + sprintf(t_buff, "%x", *cp + 512); + strcpy(op, &t_buff[strlen(t_buff)-2]); + op++; op++; + cp++; + } else { + /* + * If format character isn't an 'X', + * just copy it to the output buffer + */ + *op = *fp; + op++; + } + fp++; + } + + break; + + case T_ATM_E164_ADDR: + /* + * Print the IA5 characters of the E.164 address + */ + for(i=0; i<p->address_length; i++) { + sprintf(&strbuff[strlen(strbuff)], "%c\0", + ((Atm_addr_e164 *)p->address)->aae_addr[i]); + } + break; + + case T_ATM_SPANS_ADDR: + /* + * Get address into integers + */ + u1.c[0] = ((Atm_addr_spans *)p->address)->aas_addr[0]; + u1.c[1] = ((Atm_addr_spans *)p->address)->aas_addr[1]; + u1.c[2] = ((Atm_addr_spans *)p->address)->aas_addr[2]; + u1.c[3] = ((Atm_addr_spans *)p->address)->aas_addr[3]; + u2.c[0] = ((Atm_addr_spans *)p->address)->aas_addr[4]; + u2.c[1] = ((Atm_addr_spans *)p->address)->aas_addr[5]; + u2.c[2] = ((Atm_addr_spans *)p->address)->aas_addr[6]; + u2.c[3] = ((Atm_addr_spans *)p->address)->aas_addr[7]; + + /* + * Print the address as two words xxxxx.yyyyyyyy + */ + sprintf(strbuff, "%x.%x", u1.w, u2.w); + break; + + case T_ATM_ABSENT: + default: + strcpy(strbuff, "-"); + } + + return(strbuff); +} + + +/* + * Print the contents of a message buffer chain + * + * Arguments: + * m pointer to a buffer + * + * Returns: + * none + * + */ +void +unisig_print_mbuf(m) + KBuffer *m; +{ + int i; + caddr_t cp; + + printf("unisig_print_mbuf:\n"); + while (m) { + KB_DATASTART(m, cp, caddr_t); + for (i = 0; i < KB_LEN(m); i++) { + if (i == 0) + printf(" bfr=0x%x: ", (int)m); + printf("%x ", (u_char)*cp++); + } + printf("<end_bfr>\n"); + m = KB_NEXT(m); + } +} diff --git a/sys/netatm/uni/unisig_var.h b/sys/netatm/uni/unisig_var.h new file mode 100644 index 0000000..1e3d01a7 --- /dev/null +++ b/sys/netatm/uni/unisig_var.h @@ -0,0 +1,321 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: unisig_var.h,v 1.12 1998/07/24 20:24:34 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * Protocol control blocks + * + */ + +#ifndef _UNISIG_VAR_H +#define _UNISIG_VAR_H + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#ifdef ATM_KERNEL +/* + * Structure containing state information for each UNI protocol + * instance. There will be one instance for each ATM device interface + * using the UNI signalling manager. + */ +struct unisig { + struct siginst us_inst; /* Header */ + struct atm_time us_time; /* Timer controls */ + void (*us_lower) /* Lower command handler */ + __P((int, void *, int, int)); + Atm_connection *us_conn; /* Signalling connection */ + int us_cref; /* Call reference allocation */ + u_int us_retry; /* Protocol retry count */ + u_short us_headout; /* Headroom on sig ch output */ + u_char us_proto; /* Signalling version */ +}; + +#define us_next us_inst.si_next +#define us_pif us_inst.si_pif +#define us_addr us_inst.si_addr +#define us_subaddr us_inst.si_subaddr +#define us_vccq us_inst.si_vccq +#define us_state us_inst.si_state +#define us_ipserv us_inst.si_ipserv +#endif /* ATM_KERNEL */ + +/* + * Signalling manager states + */ +#define UNISIG_NULL 0 +#define UNISIG_ADDR_WAIT 1 +#define UNISIG_INIT 2 +#define UNISIG_ACTIVE 3 +#define UNISIG_DETACH 4 + +/* + * Signalling manager events + */ +#define UNISIG_SIGMGR_TIMEOUT 0 +#define UNISIG_SIGMGR_SSCF_EST_IND 1 +#define UNISIG_SIGMGR_SSCF_EST_CNF 2 +#define UNISIG_SIGMGR_SSCF_RLS_IND 3 +#define UNISIG_SIGMGR_SSCF_RLS_CNF 4 +#define UNISIG_SIGMGR_SSCF_DATA_IND 5 +#define UNISIG_SIGMGR_SSCF_UDATA_IND 6 +#define UNISIG_SIGMGR_CALL_CLEARED 7 +#define UNISIG_SIGMGR_DETACH 8 +#define UNISIG_SIGMGR_ADDR_SET 9 + +/* + * Signalling manager timer values + */ +#define UNISIG_SSCF_TIMEOUT (3 * ATM_HZ) + + +#ifdef ATM_KERNEL +/* + * UNI Virtual Channel Connection control block. All information + * regarding the state of a UNI-controlled VCC will be recorded here. + * There will be one UNI VCC control block for each UNI-controlled + * VCC. + */ +struct unisig_vccb { + struct vccb vcp_hdr; /* Generic VCCB */ + u_short uv_retry; /* Xmit retry count */ + u_int uv_call_ref; /* Q.2931 call reference */ +}; + +#define uv_type vcp_hdr.vc_type +#define uv_proto vcp_hdr.vc_proto +#define uv_sstate vcp_hdr.vc_sstate +#define uv_ustate vcp_hdr.vc_ustate +#define uv_pif vcp_hdr.vc_pif +#define uv_nif vcp_hdr.vc_nif +#define uv_sigelem vcp_hdr.vc_sigelem +#define uv_time vcp_hdr.vc_time +#define uv_vpi vcp_hdr.vc_vpi +#define uv_vci vcp_hdr.vc_vci +#define uv_connvc vcp_hdr.vc_connvc +#define uv_ipdus vcp_hdr.vc_ipdus +#define uv_opdus vcp_hdr.vc_opdus +#define uv_ibytes vcp_hdr.vc_ibytes +#define uv_obytes vcp_hdr.vc_obytes +#define uv_ierrors vcp_hdr.vc_ierrors +#define uv_oerrors vcp_hdr.vc_oerrors +#define uv_tstamp vcp_hdr.vc_tstamp +#endif /* ATM_KERNEL */ + +/* + * UNI VCC protocol states. Taken from The ATM Forum UNI 3.0 (section + * 5.2.1.1) + */ +#define UNI_NULL 0 /* No call exists */ +#define UNI_CALL_INITIATED 1 /* Initiating call */ +#define UNI_CALL_OUT_PROC 3 /* Outgoing call proceeding */ +#define UNI_CALL_DELIVERED 4 /* Not supported */ +#define UNI_CALL_PRESENT 6 /* Call coming in */ +#define UNI_CALL_RECEIVED 7 /* Not supported */ +#define UNI_CONNECT_REQUEST 8 /* Call coming in */ +#define UNI_CALL_IN_PROC 9 /* Incoming call proceeding */ +#define UNI_ACTIVE 10 /* Call is established */ +#define UNI_RELEASE_REQUEST 11 /* Clearing call */ +#define UNI_RELEASE_IND 12 /* Network disconnecting */ + +/* + * Additional states required for internal management of VCCs + */ +#define UNI_SSCF_RECOV 13 /* Signalling chan recovery */ +#define UNI_FREE 14 /* Waiting for user to free */ +#define UNI_PVC_ACTIVE 15 /* PVC Active */ +#define UNI_PVC_ACT_DOWN 16 /* PVC Active - i/f down */ + +/* + * UNI VCC events + */ +#define UNI_VC_TIMEOUT 0 /* Timer expired */ +#define UNI_VC_CALLP_MSG 1 /* CALL PROCEEDING message */ +#define UNI_VC_CONNECT_MSG 2 /* CONNECT message */ +#define UNI_VC_CNCTACK_MSG 3 /* CONNECT ACK message */ +#define UNI_VC_SETUP_MSG 4 /* SETUP message */ +#define UNI_VC_RELEASE_MSG 5 /* RELEASE message */ +#define UNI_VC_RLSCMP_MSG 6 /* RELEASE COMPLETE message */ +#define UNI_VC_STATUS_MSG 7 /* STATUS message */ +#define UNI_VC_STATUSENQ_MSG 8 /* STATUS ENQ message */ +#define UNI_VC_ADDP_MSG 9 /* ADD PARTY message */ +#define UNI_VC_ADDPACK_MSG 10 /* ADD PARTY ACK message */ +#define UNI_VC_ADDPREJ_MSG 11 /* ADD PARTY REJ message */ +#define UNI_VC_DROP_MSG 12 /* DROP PARTY message */ +#define UNI_VC_DROPACK_MSG 13 /* DROP PARTY ACK message */ +#define UNI_VC_SETUP_CALL 14 /* Setup routine called */ +#define UNI_VC_ACCEPT_CALL 15 /* Accept call routine called */ +#define UNI_VC_REJECT_CALL 16 /* Reject call routine called */ +#define UNI_VC_RELEASE_CALL 17 /* Release routine called */ +#define UNI_VC_ABORT_CALL 18 /* Abort routine called */ +#define UNI_VC_SAAL_FAIL 19 /* Signalling AAL failed */ +#define UNI_VC_SAAL_ESTAB 20 /* Signalling AAL back up */ + + +#ifdef ATM_KERNEL +/* + * UNI Timer Values. These values (except for T317) are taken from + * The ATM Forum UNI 3.0 (section 5.7.2). + */ +#define UNI_T303 (4 * ATM_HZ) +#define UNI_T308 (30 * ATM_HZ) +#define UNI_T309 (10 * ATM_HZ) +#define UNI_T310 (10 * ATM_HZ) +#define UNI_T313 (4 * ATM_HZ) +#define UNI_T316 (120 * ATM_HZ) +#define UNI_T317 (60 * ATM_HZ) +#define UNI_T322 (4 * ATM_HZ) +#define UNI_T398 (4 * ATM_HZ) +#define UNI_T399 (14 * ATM_HZ) + + +/* + * Timer macros + */ +#define UNISIG_TIMER(s, t) atm_timeout(&(s)->us_time, (t), unisig_timer) +#define UNISIG_CANCEL(s) atm_untimeout(&(s)->us_time) +#define UNISIG_VC_TIMER(v, t) atm_timeout(&(v)->vc_time, (t), unisig_vctimer) +#define UNISIG_VC_CANCEL(v) atm_untimeout(&(v)->vc_time) + + +/* + * Global function declarations + */ +struct usfmt; +struct unisig_msg; + + /* unisig_decode.c */ +int usf_dec_msg __P((struct usfmt *, struct unisig_msg *)); + + /* unisig_encode.c */ +int usf_enc_msg __P((struct usfmt *, struct unisig_msg *)); + + /* unisig_if.c */ +int unisig_start __P((void)); +int unisig_stop __P((void)); +int unisig_free __P((struct vccb *)); + + /* unisig_mbuf.c */ +int usf_init __P((struct usfmt *, struct unisig *, KBuffer *, int, int)); +int usf_byte __P((struct usfmt *, u_char *)); +int usf_short __P((struct usfmt *, u_short *)); +int usf_int3 __P((struct usfmt *, u_int *)); +int usf_int __P((struct usfmt *, u_int *)); +int usf_ext __P((struct usfmt *, u_int *)); +int usf_count __P((struct usfmt *)); +int usf_byte_mark __P((struct usfmt *, u_char *, u_char **)); + + /* unisig_msg.c */ +struct ie_generic; +void unisig_cause_from_attr __P((struct ie_generic *, + Atm_attributes *)); +void unisig_cause_from_msg __P((struct ie_generic *, + struct unisig_msg *, int)); +int unisig_send_msg __P((struct unisig *, + struct unisig_msg *)); +int unisig_send_setup __P((struct unisig *, + struct unisig_vccb *)); +int unisig_send_release __P((struct unisig *, + struct unisig_vccb *, + struct unisig_msg *, + int)); +int unisig_send_release_complete __P((struct unisig *, + struct unisig_vccb *, + struct unisig_msg *, + int)); +int unisig_send_status __P((struct unisig *, + struct unisig_vccb *, + struct unisig_msg *, + int)); +int unisig_rcv_msg __P((struct unisig *, KBuffer *)); + + /* unisig_print.c */ +void usp_print_msg __P((struct unisig_msg *, int)); + + /* unisig_proto.c */ +void unisig_timer __P((struct atm_time *)); +void unisig_vctimer __P((struct atm_time *)); +void unisig_saal_ctl __P((int, void *, void *)); +void unisig_saal_data __P((void *, KBuffer *)); +caddr_t unisig_getname __P((void *)); +void unisig_connected __P((void *)); +void unisig_cleared __P((void *, struct t_atm_cause *)); + + /* unisig_sigmgr_state.c */ +int unisig_sigmgr_state __P((struct unisig *, int, + KBuffer *)); + + /* unisig_subr.c */ +void unisig_set_cause_attr __P((Atm_attributes *, int)); +int unisig_open_vcc __P((struct unisig *, Atm_connvc *)); +int unisig_close_vcc __P((struct unisig *, + struct unisig_vccb *)); +int unisig_clear_vcc __P((struct unisig *, + struct unisig_vccb *, int)); +void unisig_switch_reset __P((struct unisig *, int)); +void unisig_save_attrs __P((struct unisig *, struct unisig_msg *, + Atm_attributes *)); +int unisig_set_attrs __P((struct unisig *, struct unisig_msg *, + Atm_attributes *)); + + /* unisig_util.c */ +void unisig_free_msg __P((struct unisig_msg *)); +int unisig_verify_vccb __P((struct unisig *, + struct unisig_vccb *)); +struct unisig_vccb * + unisig_find_conn __P((struct unisig *, u_int)); +struct unisig_vccb * + unisig_find_vpvc __P((struct unisig *, int, int, + u_char)); +int unisig_alloc_call_ref __P((struct unisig *)); +char * unisig_addr_print __P((Atm_addr *)); +void unisig_print_mbuf __P((KBuffer *)); +void unisig_print_buffer __P((KBuffer *)); + + /* unisig_vc_state.c */ +int unisig_vc_state __P((struct unisig *, + struct unisig_vccb *, + int, + struct unisig_msg *)); + + +/* + * External variables + */ +extern struct sp_info unisig_vcpool; +extern struct sp_info unisig_msgpool; +extern struct sp_info unisig_iepool; + +#endif /* ATM_KERNEL */ + +#endif /* _UNISIG_VAR_H */ diff --git a/sys/netatm/uni/unisig_vc_state.c b/sys/netatm/uni/unisig_vc_state.c new file mode 100644 index 0000000..cfd7635 --- /dev/null +++ b/sys/netatm/uni/unisig_vc_state.c @@ -0,0 +1,2223 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: unisig_vc_state.c,v 1.11 1998/08/06 18:16:29 mks Exp $ + * + */ + +/* + * ATM Forum UNI 3.0/3.1 Signalling Manager + * ---------------------------------------- + * + * VC state machine + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: unisig_vc_state.c,v 1.11 1998/08/06 18:16:29 mks Exp $"; +#endif + +#include <netatm/kern_include.h> + +#include <netatm/uni/unisig.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/unisig_msg.h> +#include <netatm/uni/unisig_mbuf.h> +#include <netatm/uni/unisig_decode.h> + + +/* + * Local functions + */ +static int unisig_vc_invalid __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act01 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act02 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act03 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act04 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act05 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act06 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act07 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act08 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act09 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act10 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act11 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act12 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act13 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act14 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act15 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act16 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act17 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act18 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act19 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act20 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act21 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act22 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act23 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act24 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act25 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act26 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act27 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act28 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act29 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act30 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_act31 __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)); +static int unisig_vc_clear_call __P((struct unisig *, + struct unisig_vccb *, + struct unisig_msg *, + int)); + + +/* + * State table + */ +static int unisig_vc_states[21][17] = { +/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 */ +{ 0, 2, 99, 5, 99, 99, 0, 99, 12, 99, 0, 14, 0, 3, 0, 0, 0 }, +{ 29, 4, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 }, +{ 29, 6, 99, 6, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 }, +{ 29, 17, 99, 17, 99, 99, 17, 99, 10, 99, 17, 17, 17, 0, 0, 0, 0 }, +{ 8, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 }, +{ 29, 7, 99, 15, 99, 99, 15, 99, 15, 99, 15, 16, 17, 0, 0, 0, 0 }, +{ 19, 3, 99, 3, 99, 99, 3, 99, 3, 99, 3, 13, 3, 0, 0, 0, 0 }, +{ 21, 21, 99, 21, 99, 99, 21, 99, 21, 99, 21, 21, 21, 0, 0, 0, 0 }, +{ 22, 22, 99, 22, 99, 99, 22, 99, 22, 99, 22, 22, 22, 0, 0, 0, 0 }, +{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 23, 17, 17, 0, 0, 0, 0 }, +{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 }, +{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 }, +{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 }, +{ 29, 17, 99, 17, 99, 99, 17, 99, 17, 99, 17, 17, 17, 0, 0, 0, 0 }, +{ 1, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99 }, +{ 99, 25, 99, 25, 99, 99, 9, 99, 25, 99, 25, 25, 25, 25, 31, 25, 25 }, +{ 99, 25, 99, 25, 99, 99, 11, 99, 25, 99, 25, 25, 25, 25, 19, 25, 25 }, +{ 99, 12, 99, 12, 99, 99, 25, 99, 12, 99, 12, 19, 19, 30, 19, 99, 99 }, +{ 99, 12, 99, 12, 99, 99, 12, 99, 12, 99, 12, 3, 3, 3, 24, 26, 26 }, +{ 99, 3, 99, 3, 99, 99, 30, 99, 3, 99, 18, 3, 3, 0, 19, 27, 19 }, +{ 99, 7, 99, 7, 99, 99, 30, 99, 7, 99, 19, 19, 19, 20, 19, 19, 28 } +}; + + +/* + * Action vector + * + * A given state, action pair selects an action number from the + * state table. This vector holds the address of the action routine + * for each action number. + */ +#define MAX_ACTION 32 +static int (*unisig_vc_act_vec[MAX_ACTION]) + __P((struct unisig *, struct unisig_vccb *, + struct unisig_msg *)) = { + unisig_vc_invalid, + unisig_vc_act01, + unisig_vc_act02, + unisig_vc_act03, + unisig_vc_act04, + unisig_vc_act05, + unisig_vc_act06, + unisig_vc_act07, + unisig_vc_act08, + unisig_vc_act09, + unisig_vc_act10, + unisig_vc_act11, + unisig_vc_act12, + unisig_vc_act13, + unisig_vc_act14, + unisig_vc_act15, + unisig_vc_act16, + unisig_vc_act17, + unisig_vc_act18, + unisig_vc_act19, + unisig_vc_act20, + unisig_vc_act21, + unisig_vc_act22, + unisig_vc_act23, + unisig_vc_act24, + unisig_vc_act25, + unisig_vc_act26, + unisig_vc_act27, + unisig_vc_act28, + unisig_vc_act29, + unisig_vc_act30, + unisig_vc_act31 +}; + + +/* + * Process an event on a VC + * + * Arguments: + * usp pointer to the UNISIG instance + * uvp pointer to the VCCB for the affected VCC + * event a numeric indication of which event has occured + * msg pointer to a signalling message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +unisig_vc_state(usp, uvp, event, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + int event; + struct unisig_msg *msg; +{ + int action, rc, state; + + /* + * Select an action from the state table + */ + if (uvp) + state = uvp->uv_sstate; + else + state = UNI_NULL; + action = unisig_vc_states[event][state]; + if (action >= MAX_ACTION || action < 0) + panic("unisig_vc_state: invalid action\n"); + + /* + * Perform the requested action + */ + ATM_DEBUG4("unisig_vc_state: uvp=0x%x, state=%d, event=%d, action=%d\n", + (int) uvp, state, event, action); + rc = unisig_vc_act_vec[action](usp, uvp, msg); + + return(rc); +} + + +/* + * VC state machine action 0 + * Unexpected action - log an error message + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection (may + be null) + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_invalid(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + log(LOG_ERR, "unisig_vc_state: unexpected action\n"); + return(EINVAL); +} + + +/* + * VC state machine action 1 + * Setup handler called + * + * Send SETUP, start timer T303, go to UNI_CALL_INITIATED state + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act01(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + /* + * Send the setup message + */ + rc = unisig_send_setup(usp, uvp); + if (rc) + return(rc); + + /* + * Set timer T303 + */ + uvp->uv_retry = 0; + UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T303); + + /* + * Set the new state + */ + uvp->uv_sstate = UNI_CALL_INITIATED; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + return(0); +} + + +/* + * VC state machine action 2 + * Timeout while waiting for CALL PROCEEDING or CONNECT + * + * If this is the second expiration, clear the call. Otherwise, + * retransmit the SETUP message and restart T303. + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act02(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc = 0; + + if (uvp->uv_retry) { + /* + * Clear the call + */ + rc = unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_NO_ROUTE_TO_DESTINATION); + } else { + uvp->uv_retry++; + (void) unisig_send_setup(usp, uvp); + UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T303); + } + + return(rc); +} + + +/* + * VC state machine action 3 + * + * Clear the call internally + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act03(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + /* + * Clear the VCCB + */ + rc = unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_DESTINATION_OUT_OF_ORDER); + + return(rc); +} + + +/* + * VC state machine action 4 + * Received CALL PROCEEDING + * + * Start timer T310, go to UNI_CALL_OUT_PROC + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act04(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int cause, rc, vpi, vci; + struct atm_pif *pip = usp->us_pif; + struct ie_generic *iep; + + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Make sure a Connection ID is part of the message + */ + if (msg->msg_ie_cnid) { + vpi = msg->msg_ie_cnid->ie_cnid_vpci; + vci = msg->msg_ie_cnid->ie_cnid_vci; + } else { + iep = (struct ie_generic *)atm_allocate(&unisig_iepool); + if (!iep) + return(ENOMEM); + iep->ie_ident = UNI_IE_CNID; + iep->ie_err_cause = UNI_IE_CAUS_MISSING; + MSG_IE_ADD(msg, iep, UNI_MSG_IE_ERR); + cause = UNI_IE_CAUS_MISSING; + ATM_DEBUG0("unisig_vc_act04: no CNID in Call Proc\n"); + goto response04; + } + + /* + * Make sure we can handle the specified VPI and VCI + */ + if (vpi > pip->pif_maxvpi || vci > pip->pif_maxvci || + vci < UNI_IE_CNID_MIN_VCI) { + cause = UNI_IE_CAUS_BAD_VCC; + ATM_DEBUG0("unisig_vc_act04: VPI/VCI invalid\n"); + goto response04; + } + + /* + * Make sure the specified VPI and VCI are not in use + */ + if (unisig_find_vpvc(usp, vpi, vci, VCC_OUT)) { + cause = UNI_IE_CAUS_NA_VCC; + ATM_DEBUG0("unisig_vc_act04: VPI/VCI in use\n"); + goto response04; + } + + /* + * Start timer T310 + */ + UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T310); + + /* + * Save the specified VPI and VCI + */ + uvp->uv_vpi = vpi; + uvp->uv_vci = vci; + + /* + * Set the state + */ + uvp->uv_sstate = UNI_CALL_OUT_PROC; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + return(0); + +response04: + /* + * Initiate call clearing + */ + rc = unisig_vc_clear_call(usp, uvp, msg, cause); + + return(rc); +} + + +/* + * VC state machine action 5 + * Timeout in UNI_CALL_OUT_PROC + * + * Clear call towards network + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act05(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + struct unisig_msg *rls_msg; + struct ie_generic *cause_ie; + + /* + * Send a RELEASE message + */ + rls_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool); + if (rls_msg == NULL) + return(ENOMEM); + cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool); + if (cause_ie == NULL) { + atm_free(rls_msg); + return(ENOMEM); + } + + /* + * Fill out the RELEASE message + */ + rls_msg->msg_call_ref = uvp->uv_call_ref; + rls_msg->msg_type = UNI_MSG_RLSE; + rls_msg->msg_type_flag = 0; + rls_msg->msg_type_action = 0; + rls_msg->msg_ie_caus = cause_ie; + + /* + * Fill out the cause IE + */ + cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER; + cause_ie->ie_caus_cause = UNI_IE_CAUS_TIMER; + KM_COPY("310", cause_ie->ie_caus_diagnostic, 3); + + /* + * Send the RELEASE message. + */ + rc = unisig_send_msg(usp, rls_msg); + unisig_free_msg(rls_msg); + + /* + * Start timer T308 + */ + UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T308); + + /* + * Set the new state + */ + uvp->uv_sstate = UNI_RELEASE_REQUEST; + uvp->uv_ustate = VCCU_CLOSED; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + return(rc); +} + + +/* + * VC state machine action 6 + * Received CONNECT + * + * Send CONNECT ACK, go to UNI_ACTIVE state + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act06(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int cause, rc, vci, vpi; + struct atm_pif *pip = usp->us_pif; + struct unisig_msg *cack_msg; + struct ie_generic *iep; + Atm_attributes *ap; + + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + ap = &uvp->uv_connvc->cvc_attr; + + /* + * See if a VPI/VCI is specified + */ + if (msg->msg_ie_cnid) { + /* + * Yes--VPI/VCI must be the first specification or must + * match what was specified before + */ + vpi = msg->msg_ie_cnid->ie_cnid_vpci; + vci = msg->msg_ie_cnid->ie_cnid_vci; + if ((uvp->uv_vpi || uvp->uv_vci) && + (vpi != uvp->uv_vpi || + vci != uvp->uv_vci)) { + cause = UNI_IE_CAUS_BAD_VCC; + ATM_DEBUG0("unisig_vc_act06: VPI/VCI invalid\n"); + goto response06; + } + + /* + * Specified VPI/VCI must be within range + */ + if (vpi > pip->pif_maxvpi || vci > pip->pif_maxvci || + vci < UNI_IE_CNID_MIN_VCI) { + cause = UNI_IE_CAUS_BAD_VCC; + ATM_DEBUG0("unisig_vc_act06: VPI/VCI invalid\n"); + goto response06; + } + uvp->uv_vpi = vpi; + uvp->uv_vci = vci; + } else { + /* + * No--VPI/VCI must have been specified earlier + */ + if (!uvp->uv_vpi || !uvp->uv_vci) { + iep = (struct ie_generic *)atm_allocate( + &unisig_iepool); + if (!iep) + return(ENOMEM); + iep->ie_ident = UNI_IE_CNID; + iep->ie_err_cause = UNI_IE_CAUS_MISSING; + MSG_IE_ADD(msg, iep, UNI_MSG_IE_ERR); + cause = UNI_IE_CAUS_MISSING; + ATM_DEBUG0("unisig_vc_act06: CNID missing\n"); + goto response06; + } + } + + /* + * Handle AAL parameters negotiation + */ + if (msg->msg_ie_aalp) { + struct ie_generic *aalp = msg->msg_ie_aalp; + + /* + * AAL parameters must have been sent in SETUP + */ + if ((ap->aal.tag != T_ATM_PRESENT) || + (ap->aal.type != aalp->ie_aalp_aal_type)) { + cause = UNI_IE_CAUS_IECONTENT; + goto response06; + } + + switch (aalp->ie_aalp_aal_type) { + + case UNI_IE_AALP_AT_AAL3: + /* + * Maximum SDU size negotiation + */ + if (aalp->ie_aalp_4_fwd_max_sdu == T_ATM_ABSENT) + break; + if ((ap->aal.v.aal4.forward_max_SDU_size < + aalp->ie_aalp_4_fwd_max_sdu) || + (ap->aal.v.aal4.backward_max_SDU_size < + aalp->ie_aalp_4_bkwd_max_sdu)) { + cause = UNI_IE_CAUS_IECONTENT; + goto response06; + } else { + ap->aal.v.aal4.forward_max_SDU_size = + aalp->ie_aalp_4_fwd_max_sdu; + ap->aal.v.aal4.backward_max_SDU_size = + aalp->ie_aalp_4_bkwd_max_sdu; + } + break; + + case UNI_IE_AALP_AT_AAL5: + /* + * Maximum SDU size negotiation + */ + if (aalp->ie_aalp_5_fwd_max_sdu == T_ATM_ABSENT) + break; + if ((ap->aal.v.aal5.forward_max_SDU_size < + aalp->ie_aalp_5_fwd_max_sdu) || + (ap->aal.v.aal5.backward_max_SDU_size < + aalp->ie_aalp_5_bkwd_max_sdu)) { + cause = UNI_IE_CAUS_IECONTENT; + goto response06; + } else { + ap->aal.v.aal5.forward_max_SDU_size = + aalp->ie_aalp_5_fwd_max_sdu; + ap->aal.v.aal5.backward_max_SDU_size = + aalp->ie_aalp_5_bkwd_max_sdu; + } + break; + } + } + + /* + * Get memory for a CONNECT ACK message + */ + cack_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool); + if (cack_msg == NULL) + return(ENOMEM); + + /* + * Fill out the CONNECT ACK message + */ + cack_msg->msg_call_ref = uvp->uv_call_ref; + cack_msg->msg_type = UNI_MSG_CACK; + cack_msg->msg_type_flag = 0; + cack_msg->msg_type_action = 0; + + /* + * Send the CONNECT ACK message + */ + rc = unisig_send_msg(usp, cack_msg); + unisig_free_msg(cack_msg); + + /* + * Set the new state + */ + uvp->uv_sstate = UNI_ACTIVE; + uvp->uv_ustate = VCCU_OPEN; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + /* + * Notify the user that the connection is now active + */ + atm_cm_connected(uvp->uv_connvc); + + return(0); + +response06: + /* + * Initiate call clearing + */ + rc = unisig_vc_clear_call(usp, uvp, msg, cause); + + return(rc); +} + + +/* + * VC state machine action 7 + * Abort routine called or signalling SAAL session reset while in + * one of the call setup states + * + * Clear the call, send RELEASE COMPLETE, notify the user. + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act07(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Send a RELEASE COMPLETE message rejecting the connection + */ + rc = unisig_send_release_complete(usp, uvp, msg, + UNI_IE_CAUS_TEMP); + + /* + * Clear the call VCCB + */ + uvp->uv_sstate = UNI_FREE; + uvp->uv_ustate = VCCU_CLOSED; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + /* + * Notify the user + */ + unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + atm_cm_cleared(uvp->uv_connvc); + + return(rc); +} + + +/* + * VC state machine action 8 + * Received SETUP + * + * Check call paramaters, notify user that a call has been received, + * set UNI_CALL_PRESENT state + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act08(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int cause = 0, rc, vpi, vci; + struct atm_pif *pip = usp->us_pif; + struct atm_nif *nip; + Atm_addr_nsap *nap; + Atm_attributes attr; + + ATM_DEBUG3("unisig_vc_act08: usp=0x%x, uvp=0x%x, msg=0x%x\n", + (int) usp, (int) uvp, (int) msg); + + /* + * Make sure that the called address is the right format + */ + if (msg->msg_ie_cdad->ie_cdad_plan != UNI_IE_CDAD_PLAN_NSAP) { + cause = UNI_IE_CAUS_IECONTENT; + ATM_DEBUG0("unisig_vc_act08: bad address format\n"); + goto response08; + } + + /* + * Make sure that the called address is ours + */ + nap = (Atm_addr_nsap *) msg->msg_ie_cdad->ie_cdad_addr.address; + if (bcmp(usp->us_addr.address, nap, /* XXX */ + sizeof(Atm_addr_nsap)-1)) { + cause = UNI_IE_CAUS_IECONTENT; + ATM_DEBUG0("unisig_vc_act08: address not mine\n"); + goto response08; + } + + /* + * Find the right NIF for the given selector byte + */ + nip = pip->pif_nif; + while (nip && nip->nif_sel != nap->aan_sel) { + nip = nip->nif_pnext; + } + if (!nip) { + cause = UNI_IE_CAUS_IECONTENT; + ATM_DEBUG0("unisig_vc_act08: bad selector byte\n"); + goto response08; + } + + /* + * See if we can handle the specified encapsulation + */ + if (msg->msg_ie_blli->ie_blli_l2_id != UNI_IE_BLLI_L2P_LLC && + (msg->msg_ie_blli->ie_blli_l2_id != 0 || + msg->msg_ie_blli->ie_blli_l3_id != + UNI_IE_BLLI_L3P_ISO9577)) { + cause = UNI_IE_CAUS_UNAVAIL; + ATM_DEBUG0("unisig_vc_act08: bad encapsulation\n"); + goto response08; + } + + /* + * See if we recognize the specified AAL + */ + if (msg->msg_ie_aalp->ie_aalp_aal_type != UNI_IE_AALP_AT_AAL3 && + msg->msg_ie_aalp->ie_aalp_aal_type != + UNI_IE_AALP_AT_AAL5) { + cause = UNI_IE_CAUS_UAAL; + ATM_DEBUG0("unisig_vc_act08: bad AAL\n"); + goto response08; + } + + /* + * Should verify that we can handle requested + * connection QOS + */ + + /* + * Make sure the specified VPI/VCI is valid + */ + vpi = msg->msg_ie_cnid->ie_cnid_vpci; + vci = msg->msg_ie_cnid->ie_cnid_vci; + if (vpi > pip->pif_maxvpi || + vci > pip->pif_maxvci || + vci < UNI_IE_CNID_MIN_VCI) { + cause = UNI_IE_CAUS_BAD_VCC; + ATM_DEBUG0("unisig_vc_act08: VPI/VCI invalid\n"); + goto response08; + } + + /* + * Make sure the specified VPI/VCI isn't in use already + */ + if (unisig_find_vpvc(usp, vpi, vci, VCC_IN)) { + cause = UNI_IE_CAUS_NA_VCC; + ATM_DEBUG0("unisig_vc_act08: VPI/VCI in use\n"); + goto response08; + } + + /* + * Make sure it's a point-to-point connection + */ + if (msg->msg_ie_bbcp->ie_bbcp_conn_config != + UNI_IE_BBCP_CC_PP) { + cause = UNI_IE_CAUS_NI_BC; + ATM_DEBUG0("unisig_vc_act08: conn not pt-pt\n"); + goto response08; + } + + /* + * Fill in the VCCB fields that we can at this point + */ + uvp->uv_type = VCC_SVC | VCC_IN | VCC_OUT; + uvp->uv_proto = pip->pif_sigmgr->sm_proto; + uvp->uv_sstate = UNI_CALL_PRESENT; + uvp->uv_ustate = VCCU_POPEN; + uvp->uv_pif = pip; + uvp->uv_nif = nip; + uvp->uv_vpi = msg->msg_ie_cnid->ie_cnid_vpci; + uvp->uv_vci = msg->msg_ie_cnid->ie_cnid_vci; + uvp->uv_tstamp = time_second; + + /* + * Copy the connection attributes from the SETUP message + * to an attribute block + */ + KM_ZERO(&attr, sizeof(attr)); + attr.nif = nip; + attr.aal.tag = T_ATM_ABSENT; + attr.traffic.tag = T_ATM_ABSENT; + attr.bearer.tag = T_ATM_ABSENT; + attr.bhli.tag = T_ATM_ABSENT; + attr.blli.tag_l2 = T_ATM_ABSENT; + attr.blli.tag_l3 = T_ATM_ABSENT; + attr.llc.tag = T_ATM_ABSENT; + attr.called.tag = T_ATM_ABSENT; + attr.calling.tag = T_ATM_ABSENT; + attr.qos.tag = T_ATM_ABSENT; + attr.transit.tag = T_ATM_ABSENT; + attr.cause.tag = T_ATM_ABSENT; + unisig_save_attrs(usp, msg, &attr); + + /* + * Notify the connection manager of the new VCC + */ + ATM_DEBUG0("unisig_vc_act08: notifying user of connection\n"); + rc = atm_cm_incoming((struct vccb *)uvp, &attr); + if (rc) + goto response08; + + /* + * Wait for the connection recipient to issue an accept + * or reject + */ + return(0); + +response08: + ATM_DEBUG1("unisig_vc_act08: reject with cause=%d\n", cause); + + /* + * Clear the VCCB state + */ + uvp->uv_sstate = UNI_NULL; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + /* + * Some problem was detected with the request. Send a Q.2931 + * message rejecting the connection. + */ + rc = unisig_send_release_complete(usp, uvp, msg, cause); + + return(rc); +} + + +/* + * VC state machine action 9 + * Accept routine called by user + * + * Send CONNECT, start timer T313, go to UNI_CONNECT_REQUEST state + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act09(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + struct unisig_msg *conn_msg; + + conn_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool); + if (conn_msg == NULL) + return(ENOMEM); + + /* + * Fill out the response + */ + conn_msg->msg_call_ref = uvp->uv_call_ref; + conn_msg->msg_type = UNI_MSG_CONN; + conn_msg->msg_type_flag = 0; + conn_msg->msg_type_action = 0; + + /* + * Send the CONNECT message. If the send fails, the other + * side will eventually time out and close the connection. + */ + rc = unisig_send_msg(usp, conn_msg); + unisig_free_msg(conn_msg); + if (rc) { + return(rc); + } + + /* + * Start timer T313 + */ + UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T313); + + /* + * Set the new state + */ + uvp->uv_sstate = UNI_CONNECT_REQUEST; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + return(0); +} + + +/* + * VC state machine action 10 + * Received CONNECT ACK + * + * Go to UNI_ACTIVE state + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act10(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Set the state + */ + uvp->uv_sstate = UNI_ACTIVE; + uvp->uv_ustate = VCCU_OPEN; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + /* + * Notify the user that the call is up + */ + atm_cm_connected(uvp->uv_connvc); + + return (0); +} + + +/* + * VC state machine action 11 + * Reject handler called + * + * Send RELEASE COMPLETE, clear the call + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act11(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + /* + * Send a RELEASE COMPLETE message + */ + rc = unisig_send_release_complete(usp, uvp, msg, + UNI_IE_CAUS_REJECT); + + /* + * Clear the call VCCB + */ + uvp->uv_sstate = UNI_FREE; + uvp->uv_ustate = VCCU_CLOSED; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + return(rc); +} + + +/* + * VC state machine action 12 + * Release or abort routine called + * + * Send RELEASE, start timer T308, go to UNI_RELEASE_REQUEST state + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act12(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Send the RELEASE message + */ + rc = unisig_vc_clear_call(usp, uvp, (struct unisig_msg *)0, + T_ATM_ABSENT); + + return(rc); +} + + +/* + * VC state machine action 13 + * RELEASE COMPLETE received + * + * Clear the call + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act13(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Set the state + */ + uvp->uv_sstate = UNI_FREE; + if (uvp->uv_ustate != VCCU_ABORT) + uvp->uv_ustate = VCCU_CLOSED; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + /* + * Notify the user that the call is now closed + */ + unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + atm_cm_cleared(uvp->uv_connvc); + + return(0); +} + + +/* + * VC state machine action 14 + * Timer expired while waiting for RELEASE COMPLETE + * + * If this is the second expiration, just clear the call. Otherwise, + * retransmit the RELEASE message and restart timer T308. + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act14(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + /* + * Check the retry count + */ + if (uvp->uv_retry) { + /* + * Clear the connection + */ + rc = unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + } else { + /* + * Increment the retry count + */ + uvp->uv_retry++; + + /* + * Resend the RELEASE message + */ + rc = unisig_send_release(usp, uvp, + (struct unisig_msg *)0, T_ATM_ABSENT); + if (rc) + return(rc); + + /* + * Restart timer T308 + */ + UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T308); + } + + return(0); +} + + +/* + * VC state machine action 15 + * RELEASE received in UNI_ACTIVE state + * + * Send RELEASE COMPLETE, go to UNI_FREE, notify the user + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act15(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int cause, rc; + struct ie_generic *iep; + + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * If there was no Cause IE, flag an error + */ + if (!msg->msg_ie_caus) { + cause = UNI_IE_CAUS_MISSING; + for (iep=msg->msg_ie_err; iep; iep=iep->ie_next) { + if (iep->ie_ident == UNI_IE_CAUS && + iep->ie_err_cause == + UNI_IE_CAUS_IECONTENT) { + cause = UNI_IE_CAUS_IECONTENT; + } + } + if (cause == UNI_IE_CAUS_MISSING) { + iep = (struct ie_generic *)atm_allocate( + &unisig_iepool); + if (!iep) + return(ENOMEM); + iep->ie_ident = UNI_IE_CNID; + iep->ie_err_cause = UNI_IE_CAUS_MISSING; + MSG_IE_ADD(msg, iep, UNI_MSG_IE_ERR); + } + } else { + cause = UNI_IE_CAUS_NORM_UNSP; + } + + /* + * Send a RELEASE COMPLETE message + */ + rc = unisig_send_release_complete(usp, uvp, msg, cause); + + /* + * Set the state + */ + uvp->uv_sstate = UNI_FREE; + uvp->uv_ustate = VCCU_CLOSED; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + /* + * Notify the user that the call is cleared + */ + unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + atm_cm_cleared(uvp->uv_connvc); + + return(rc); +} + + +/* + * VC state machine action 16 + * RELEASE received in UNI_RELEASE_REQUEST state + * + * Clear the call + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act16(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Clear the VCCB + */ + rc = unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + + return(rc); +} + + +/* + * VC state machine action 17 + * Protocol error + * + * Send a STATUS message with cause 101, "message not compatible with + * call state" + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act17(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + ATM_DEBUG3("unisig_vc_perror: usp=0x%x, uvp=0x%x, msg=0x%x\n", + (int) usp, (int) uvp, (int) msg); + + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Send a STATUS message + */ + rc = unisig_send_status(usp, uvp, msg, UNI_IE_CAUS_STATE); + + return(rc ? rc : EINVAL); +} + + +/* + * VC state machine action 18 + * Signalling AAL connection has been lost + * + * Start timer T309. If the timer expires before the SAAL connection + * comes back, the VCC will be cleared. + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act18(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Start timer T309 + */ + UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T309); + + /* + * Set new state + */ + uvp->uv_sstate = UNI_SSCF_RECOV; + + return(0); +} + + +/* + * VC state machine action 19 + * Ignore the event + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act19(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + return(0); +} + + +/* + * VC state machine action 20 + * SSCF establish indication in UNI_SSCF_RECOV state -- signalling + * AAL has come up after an outage + * + * Send STATUS ENQ to make sure we're in compatible state with other end + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act20(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + struct unisig_msg *stat_msg; + + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Get memory for a STATUS ENQUIRY message + */ + stat_msg = (struct unisig_msg *)atm_allocate(&unisig_msgpool); + if (stat_msg == NULL) + return(ENOMEM); + + /* + * Fill out the message + */ + stat_msg->msg_call_ref = uvp->uv_call_ref; + stat_msg->msg_type = UNI_MSG_SENQ; + stat_msg->msg_type_flag = 0; + stat_msg->msg_type_action = 0; + + /* + * Send the STATUS ENQUIRY message + */ + rc = unisig_send_msg(usp, stat_msg); + unisig_free_msg(stat_msg); + + /* + * Return to active state + */ + uvp->uv_sstate = UNI_ACTIVE; + + return(rc); +} + + +/* + * VC state machine action 21 + * STATUS received + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection (may + * be NULL) + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act21(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int cause, rc; + + /* + * Ignore a STATUS message with the global call reference + */ + if (GLOBAL_CREF(msg->msg_call_ref)) { + return(0); + } + + /* + * If the network thinks we're in NULL state, clear the VCC + */ + if (msg->msg_ie_clst->ie_clst_state == UNI_NULL) { + if (uvp) { + (void)unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_DESTINATION_OUT_OF_ORDER); + } + return(0); + } + + /* + * If we are in NULL state, send a RELEASE COMPLETE + */ + if (!uvp || (uvp->uv_sstate == UNI_FREE) || + (uvp->uv_sstate == UNI_NULL)) { + rc = unisig_send_release_complete(usp, + uvp, msg, UNI_IE_CAUS_STATE); + return(rc); + } + + /* + * If the reported state doesn't match our state, close the VCC + * unless we're in UNI_RELEASE_REQUEST or UNI_RELEASE_IND + */ + if (msg->msg_ie_clst->ie_clst_state != uvp->uv_sstate) { + if (uvp->uv_sstate == UNI_RELEASE_REQUEST || + uvp->uv_sstate == UNI_RELEASE_IND) { + return(0); + } + rc = unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + } + + /* + * States match, check for an error on one of our messages + */ + cause = msg->msg_ie_caus->ie_caus_cause; + if (cause == UNI_IE_CAUS_MISSING || + cause == UNI_IE_CAUS_MTEXIST || + cause == UNI_IE_CAUS_IEEXIST || + cause == UNI_IE_CAUS_IECONTENT || + cause == UNI_IE_CAUS_STATE) { + ATM_DEBUG2("unisig_vc_act21: error %d on message 0x%x\n", + cause, + msg->msg_ie_caus->ie_caus_diagnostic[0]); + if (uvp) { + (void)unisig_clear_vcc(usp, uvp, + T_ATM_CAUSE_INVALID_INFO_ELEMENT_CONTENTS); + } + } + + return(0); +} + + +/* + * VC state machine action 22 + * Received STATUS ENQ + * + * Send STATUS with cause 30 "response to STATUS ENQUIRY" and + * current state + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection (may + * be NULL) + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act22(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + struct unisig_msg *status; + struct ie_generic *callst_ie, *cause_ie; + + ATM_DEBUG3("unisig_vc_perror: usp=0x%x, uvp=0x%x, msg=0x%x\n", + (int) usp, (int) uvp, (int) msg); + + /* + * Get memory for a STATUS message + */ + status = (struct unisig_msg *) atm_allocate(&unisig_msgpool); + if (status == NULL) + return(ENOMEM); + callst_ie = (struct ie_generic *) atm_allocate(&unisig_iepool); + if (callst_ie == NULL) { + atm_free(status); + return(ENOMEM); + } + cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool); + if (cause_ie == NULL) { + atm_free(status); + atm_free(callst_ie); + return(ENOMEM); + } + + /* + * Fill out the response + */ + if (uvp) { + status->msg_call_ref = uvp->uv_call_ref; + } else if (msg) { + if (msg->msg_call_ref & UNI_MSG_CALL_REF_RMT) + status->msg_call_ref = msg->msg_call_ref & + UNI_MSG_CALL_REF_MASK; + else + status->msg_call_ref = msg->msg_call_ref | + UNI_MSG_CALL_REF_RMT; + } else { + status->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL; + } + status->msg_type = UNI_MSG_STAT; + status->msg_type_flag = 0; + status->msg_type_action = 0; + status->msg_ie_clst = callst_ie; + status->msg_ie_caus = cause_ie; + + /* + * Fill out the call state IE + */ + callst_ie->ie_ident = UNI_IE_CLST; + callst_ie->ie_coding = 0; + callst_ie->ie_flag = 0; + callst_ie->ie_action = 0; + if (uvp) { + switch(uvp->uv_sstate) { + case UNI_FREE: + callst_ie->ie_clst_state = UNI_NULL; + break; + default: + callst_ie->ie_clst_state = uvp->uv_sstate; + } + } else { + callst_ie->ie_clst_state = UNI_NULL; + } + + /* + * Fill out the cause IE + */ + cause_ie->ie_ident = UNI_IE_CAUS; + cause_ie->ie_coding = 0; + cause_ie->ie_flag = 0; + cause_ie->ie_action = 0; + cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER; + cause_ie->ie_caus_cause = UNI_IE_CAUS_SENQ; + + /* + * Send the STATUS message + */ + rc = unisig_send_msg(usp, status); + unisig_free_msg(status); + return(rc); +} + + +/* + * VC state machine action 23 + * Received ADD PARTY + * + * We don't support multipoint connections, so send an ADD PARTY REJECT + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act23(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + struct unisig_msg *apr_msg; + + /* + * Get memory for the ADD PARTY REJECT message + */ + apr_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool); + if (apr_msg == NULL) + return(ENOMEM); + + /* + * Fill out the message + */ + if (msg->msg_call_ref & UNI_MSG_CALL_REF_RMT) + apr_msg->msg_call_ref = msg->msg_call_ref & + UNI_MSG_CALL_REF_MASK; + else + apr_msg->msg_call_ref = msg->msg_call_ref | + UNI_MSG_CALL_REF_RMT; + apr_msg->msg_type = UNI_MSG_ADPR; + apr_msg->msg_type_flag = 0; + apr_msg->msg_type_action = 0; + + /* + * Use the endpoint reference IE from the received message + */ + apr_msg->msg_ie_eprf = msg->msg_ie_eprf; + + /* + * Send the ADD PARTY REJECT message + */ + rc = unisig_send_msg(usp, apr_msg); + apr_msg->msg_ie_eprf = NULL; + unisig_free_msg(apr_msg); + + return(rc); +} + + +/* + * VC state machine action 24 + * User error + * + * Return EALREADY + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act24(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + return(EALREADY); +} + + +/* + * VC state machine action 25 + * User error + * + * Return EINVAL + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act25(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + return(EINVAL); +} + + +/* + * VC state machine action 26 + * PVC abort + * + * The abort handler was called to abort a PVC. Clear the VCCB and + * notify the user. + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act26(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Close the VCCB + */ + rc = unisig_close_vcc(usp, uvp); + if (rc) + return(rc); + + /* + * Notify the user + */ + unisig_set_cause_attr(&uvp->uv_connvc->cvc_attr, + T_ATM_CAUSE_NORMAL_CALL_CLEARING); + atm_cm_cleared(uvp->uv_connvc); + + return(0); +} + + +/* + * VC state machine action 27 + * Signalling AAL failure + * + * Change PVC state to UNI_PVC_ACT_DOWN. + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act27(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + /* + * Set the state + */ + uvp->uv_sstate = UNI_PVC_ACT_DOWN; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + return(0); +} + + +/* + * VC state machine action 28 + * Signalling AAL established + * + * Set PVC state to UNI_PVC_ACTIVE. + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act28(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + /* + * Set the state + */ + uvp->uv_sstate = UNI_PVC_ACTIVE; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + return(0); +} + + +/* + * VC state machine action 29 + * Protocol error + * + * Send a RELEASE COMPLETE message with cause 81, "invalid call + * reference value" + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection (may + * be NULL) + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act29(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + int rc; + + /* + * Send a RELEASE COMPLETE message + */ + rc = unisig_send_release_complete(usp, uvp, msg, + UNI_IE_CAUS_CREF); + + return(rc); +} + + +/* + * VC state machine action 30 + * Release routine called while SSCF session down, or SSCF session + * reset or lost while in UNI_CALL_PRESENT + * + * Go to UNI_FREE state + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act30(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + /* + * Clear any running timer + */ + UNISIG_VC_CANCEL((struct vccb *) uvp); + + /* + * Clear the call state + */ + uvp->uv_sstate = UNI_FREE; + uvp->uv_ustate = VCCU_CLOSED; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + return(0); +} + + +/* + * VC state machine action 31 + * Accept handler called in UNI_FREE state. + * + * The call was in UNI_CALL_PRESENT state when it was closed because + * of an SSCF failure. Return an error indication. The accept + * handler will free the VCCB and return the proper code to the + * caller. + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to a UNISIG message structure + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_act31(usp, uvp, msg) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; +{ + return(ENETDOWN); +} + + +/* + * Initiate clearing a call by sending a RELEASE message. + * + * Arguments: + * usp pointer to protocol instance block + * uvp pointer to the VCCB for the affected connection + * msg pointer to UNI signalling message that the RELEASE + * responds to (may be NULL) + * cause the reason for clearing the call; a value of + * T_ATM_ABSENT indicates that the cause code is + * in the VCC's ATM attributes block + * + * Returns: + * 0 success + * errno error encountered + * + */ +static int +unisig_vc_clear_call(usp, uvp, msg, cause) + struct unisig *usp; + struct unisig_vccb *uvp; + struct unisig_msg *msg; + int cause; +{ + int rc; + + /* + * Clear the retry count + */ + uvp->uv_retry = 0; + + /* + * Make sure the ATM attributes block has a valid cause code, + * if needed + */ + if (cause == T_ATM_ABSENT && + uvp->uv_connvc->cvc_attr.cause.tag != + T_ATM_PRESENT) { + uvp->uv_connvc->cvc_attr.cause.tag = T_ATM_PRESENT; + uvp->uv_connvc->cvc_attr.cause.v.coding_standard = + T_ATM_ITU_CODING; + uvp->uv_connvc->cvc_attr.cause.v.location = + T_ATM_LOC_USER; + uvp->uv_connvc->cvc_attr.cause.v.cause_value = + usp->us_proto == ATM_SIG_UNI30 ? + T_ATM_CAUSE_UNSPECIFIED_NORMAL : + T_ATM_CAUSE_NORMAL_CALL_CLEARING; + } + + /* + * Send a RELEASE message + */ + rc = unisig_send_release(usp, uvp, msg, cause); + if (rc) + return(rc); + + /* + * Start timer T308 + */ + UNISIG_VC_TIMER((struct vccb *) uvp, UNI_T308); + + /* + * Set the VCCB state + */ + uvp->uv_sstate = UNI_RELEASE_REQUEST; + if (uvp->uv_ustate != VCCU_ABORT) + uvp->uv_ustate = VCCU_CLOSED; + + /* + * Mark the time + */ + uvp->uv_tstamp = time_second; + + return(0); +} diff --git a/usr.sbin/atm/Makefile b/usr.sbin/atm/Makefile new file mode 100644 index 0000000..a32385f --- /dev/null +++ b/usr.sbin/atm/Makefile @@ -0,0 +1,33 @@ +# +# +# =================================== +# 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. +# +# @(#) $Id: Makefile,v 1.5 1998/07/10 16:01:58 jpt Exp $ +# +# + +SUBDIR= atmarpd \ + scspd + +.include <bsd.subdir.mk> diff --git a/usr.sbin/atm/Makefile.inc b/usr.sbin/atm/Makefile.inc new file mode 100644 index 0000000..bcc3406 --- /dev/null +++ b/usr.sbin/atm/Makefile.inc @@ -0,0 +1,30 @@ +# +# +# =================================== +# 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. +# +# @(#) $Id: Makefile,v 1.5 1998/07/10 16:01:58 jpt Exp $ +# +# + +BINDIR?= /usr/sbin diff --git a/usr.sbin/atm/atmarpd/Makefile b/usr.sbin/atm/atmarpd/Makefile new file mode 100644 index 0000000..7a4ca81 --- /dev/null +++ b/usr.sbin/atm/atmarpd/Makefile @@ -0,0 +1,38 @@ +# +# +# =================================== +# 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. +# +# @(#) $Id: Makefile,v 1.5 1998/07/10 16:01:58 jpt Exp $ +# +# + +PROG= atmarpd +SRCS= atmarpd.c atmarp_config.c atmarp_log.c atmarp_scsp.c \ + atmarp_subr.c atmarp_timer.c +MAN8= atmarpd.8 + +CFLAGS+= -I ${.CURDIR}/../../../sys +LDADD+= -latm -lmd + +.include <bsd.prog.mk> diff --git a/usr.sbin/atm/atmarpd/atmarp_config.c b/usr.sbin/atm/atmarpd/atmarp_config.c new file mode 100644 index 0000000..5a4b78d --- /dev/null +++ b/usr.sbin/atm/atmarpd/atmarp_config.c @@ -0,0 +1,130 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atmarp_config.c,v 1.5 1998/08/13 20:11:11 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP-ATMARP server interface: configuration support + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atmarp_config.c,v 1.5 1998/08/13 20:11:11 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "../scspd/scsp_msg.h" +#include "../scspd/scsp_if.h" +#include "../scspd/scsp_var.h" +#include "atmarp_var.h" + + +/* + * Configure network interface for ATMARP cache synchronization + * + * Verify the network interface name and set the appropriate fields + * in the ATMARP interface entry. + * + * Arguments: + * netif pointer to network interface name + * + * Returns: + * 0 success + * errno reason for failure + * + */ +int +atmarp_cfg_netif(netif) + char *netif; +{ + int rc; + Atmarp_intf *aip = (Atmarp_intf *)0; + Atm_addr_nsap *anp; + + /* + * Get an ATMARP interface block + */ + aip = (Atmarp_intf *)UM_ALLOC(sizeof(Atmarp_intf)); + if (!aip) + atmarp_mem_err("atmarp_cfg_netif: sizeof(Atmarp_intf)"); + UM_ZERO(aip, sizeof(Atmarp_intf)); + + /* + * Make sure we're configuring a valid + * network interface + */ + rc = verify_nif_name(netif); + if (rc == 0) { + fprintf(stderr, "%s: \"%s\" is not a valid network interface\n", + prog, netif); + rc = EINVAL; + goto cfg_fail; + } else if (rc < 0) { + rc = errno; + fprintf(stderr, "%s: can't verify network interface \"%s\"\n", + prog, netif); + goto cfg_fail; + } + + /* + * Update the interface entry + */ + strcpy(aip->ai_intf, netif); + aip->ai_state = AI_STATE_NULL; + aip->ai_scsp_sock = -1; + LINK2TAIL(aip, Atmarp_intf, atmarp_intf_head, ai_next); + + return(0); + +cfg_fail: + if (aip) + UM_FREE(aip); + + return(rc); +} diff --git a/usr.sbin/atm/atmarpd/atmarp_log.c b/usr.sbin/atm/atmarpd/atmarp_log.c new file mode 100644 index 0000000..8de5415 --- /dev/null +++ b/usr.sbin/atm/atmarpd/atmarp_log.c @@ -0,0 +1,148 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atmarp_log.c,v 1.1 1998/07/24 17:11:51 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP-ATMARP server interface: logging routines + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: atmarp_log.c,v 1.1 1998/07/24 17:11:51 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "../scspd/scsp_msg.h" +#include "../scspd/scsp_if.h" +#include "../scspd/scsp_var.h" +#include "atmarp_var.h" + +#if __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + + +/* + * Write a message to atmarpd's log + * + * Arguments: + * level the level (error, info, etc.) of the message + * fmt printf-style format string + * ... parameters for printf-style use according to fmt + * + * Returns: + * none + * + */ +void +#if __STDC__ +atmarp_log(const int level, const char *fmt, ...) +#else +atmarp_log(level, fmt, va_alist) + int level; + char *fmt; + va_dcl +#endif +{ + va_list ap; + +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + + /* + * In debug mode, just write to stdout + */ + if (atmarp_debug_mode) { + vprintf(fmt, ap); + printf("\n"); + return; + } + + /* + * Check whether we have a log file set up + */ + if (!atmarp_log_file) { + /* + * Write to syslog + */ + vsyslog(level, fmt, ap); + } else { + /* + * Write to the log file + */ + vfprintf(atmarp_log_file, fmt, ap); + fprintf(atmarp_log_file, "\n"); + } + + va_end(ap); +} + + +/* + * Log a memory error and exit + * + * Arguments: + * cp message to log + * + * Returns: + * exits, does not return + * + */ +void +atmarp_mem_err(cp) + char *cp; +{ + atmarp_log(LOG_CRIT, "out of memory: %s", cp); + exit(2); +} diff --git a/usr.sbin/atm/atmarpd/atmarp_scsp.c b/usr.sbin/atm/atmarpd/atmarp_scsp.c new file mode 100644 index 0000000..e063821 --- /dev/null +++ b/usr.sbin/atm/atmarpd/atmarp_scsp.c @@ -0,0 +1,792 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atmarp_scsp.c,v 1.6 1998/08/13 20:11:11 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP-ATMARP server interface: SCSP/ATMARP interface code + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atmarp_scsp.c,v 1.6 1998/08/13 20:11:11 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> +#include <netatm/uni/uniip_var.h> + +#include <libatm.h> +#include "../scspd/scsp_msg.h" +#include "../scspd/scsp_if.h" +#include "../scspd/scsp_var.h" +#include "atmarp_var.h" + + +/* + * Send the cache for a LIS to SCSP + * + * + * Arguments: + * aip pointer to interface block + * + * Returns: + * 0 cache sent to SCSP OK + * errno reason for failure + * + */ +int +atmarp_scsp_cache(aip, msg) + Atmarp_intf *aip; + Scsp_if_msg *msg; +{ + int i, len, rc = 0; + Atmarp *aap; + Scsp_if_msg *smp = (Scsp_if_msg *)0; + Scsp_atmarp_msg *sap; + + /* + * Figure out how big the message needs to be + */ + len = sizeof(Scsp_if_msg_hdr); + for (i = 0; i < ATMARP_HASHSIZ; i++) { + for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) { + len += sizeof(Scsp_atmarp_msg); + } + } + + /* + * Get memory for the cache message + */ + smp = (Scsp_if_msg *)UM_ALLOC(len); + if (!smp) { + atmarp_mem_err("atmarp_scsp_cache: len"); + } + UM_ZERO(smp, len); + + /* + * Set header fields in SCSP message + */ + smp->si_type = SCSP_CACHE_RSP; + smp->si_proto = SCSP_PROTO_ATMARP; + smp->si_len = len; + smp->si_tok = msg->si_tok; + + /* + * Loop through the cache, adding each entry to the SCSP + * Cache Response message + */ + sap = &smp->si_atmarp; + for (i = 0; i < ATMARP_HASHSIZ; i++) { + for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) { + sap->sa_state = SCSP_ASTATE_NEW; + sap->sa_cpa = aap->aa_dstip; + ATM_ADDR_COPY(&aap->aa_dstatm, &sap->sa_cha); + ATM_ADDR_COPY(&aap->aa_dstatmsub, &sap->sa_csa); + sap->sa_key = aap->aa_key; + sap->sa_oid = aap->aa_oid; + sap->sa_seq = aap->aa_seq; + sap++; + } + } + + /* + * Send the message to SCSP + */ + rc = atmarp_scsp_out(aip, (char *)smp, len); + + /* + * Free the message + */ +cache_done: + if (smp) + UM_FREE(smp); + + return(rc); +} + + +/* + * Answer a reqeust for information about a cache entry + * + * Arguments: + * aap pointer to entry + * state entry's new state + * + * Returns: + * 0 success + * errno reason for failure + * + */ +int +atmarp_scsp_solicit(aip, smp) + Atmarp_intf *aip; + Scsp_if_msg *smp; +{ + int i, rc = 0; + Atmarp *aap; + Scsp_if_msg *rsp = (Scsp_if_msg *)0; + + /* + * Search the interface's ATMARP cache for an entry with + * the specified cache key and origin ID + */ + for (i = 0; i < ATMARP_HASHSIZ; i++) { + for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) { + if (KEY_EQUAL(&aap->aa_key, + &smp->si_sum.ss_key) && + OID_EQUAL(&aap->aa_oid, + &smp->si_sum.ss_oid)) + break; + } + if (aap) + break; + } + + /* + * Get storage for a Solicit Response + */ + rsp = (Scsp_if_msg *)UM_ALLOC(sizeof(Scsp_if_msg)); + if (!rsp) { + atmarp_mem_err("atmarp_scsp_solicit: sizeof(Scsp_if_msg)"); + } + UM_ZERO(rsp, sizeof(Scsp_if_msg)); + + /* + * Fill out the Solicit Rsp + */ + rsp->si_type = SCSP_SOLICIT_RSP; + rsp->si_proto = smp->si_proto; + rsp->si_tok = smp->si_tok; + + if (aap) { + /* + * Copy fields from the ATMARP entry to the SCSP + * Update Request message + */ + rsp->si_rc = SCSP_RSP_OK; + rsp->si_len = sizeof(Scsp_if_msg_hdr) + + sizeof(Scsp_atmarp_msg); + rsp->si_atmarp.sa_state = SCSP_ASTATE_UPD; + rsp->si_atmarp.sa_cpa = aap->aa_dstip; + ATM_ADDR_COPY(&aap->aa_dstatm, &rsp->si_atmarp.sa_cha); + ATM_ADDR_COPY(&aap->aa_dstatmsub, &rsp->si_atmarp.sa_csa); + rsp->si_atmarp.sa_key = aap->aa_key; + rsp->si_atmarp.sa_oid = aap->aa_oid; + rsp->si_atmarp.sa_seq = aap->aa_seq; + } else { + /* + * Entry not found--set return code + */ + rsp->si_rc = SCSP_RSP_NOT_FOUND; + rsp->si_len = smp->si_len; + rsp->si_sum = smp->si_sum; + } + + /* + * Send the message to SCSP + */ + rc = atmarp_scsp_out(aip, (char *)rsp, rsp->si_len); + UM_FREE(rsp); + + return(rc); +} + + +/* + * Send a cache update to SCSP + * + * Arguments: + * aap pointer to entry + * state entry's new state + * + * Returns: + * 0 success + * errno reason for failure + * + */ +int +atmarp_scsp_update(aap, state) + Atmarp *aap; + int state; +{ + int i, len, rc = 0; + Atmarp_intf *aip = aap->aa_intf; + Scsp_if_msg *smp = (Scsp_if_msg *)0; + Scsp_atmarp_msg *sap; + + /* + * Make sure the connection to SCSP is active + */ + if (aip->ai_state == AI_STATE_NULL) { + return(0); + } + + /* + * Get memory for the cache message + */ + smp = (Scsp_if_msg *)UM_ALLOC(sizeof(Scsp_if_msg)); + if (!smp) { + atmarp_mem_err("atmarp_scsp_update: sizeof(Scsp_if_msg)"); + } + UM_ZERO(smp, sizeof(Scsp_if_msg)); + + /* + * Set header fields in SCSP message + */ + smp->si_type = SCSP_UPDATE_REQ; + smp->si_proto = SCSP_PROTO_ATMARP; + smp->si_len = sizeof(Scsp_if_msg_hdr) + sizeof(Scsp_atmarp_msg); + + /* + * Copy fields from the ATMARP entry to the SCSP + * Update Request message + */ + smp->si_atmarp.sa_state = state; + smp->si_atmarp.sa_cpa = aap->aa_dstip; + ATM_ADDR_COPY(&aap->aa_dstatm, &smp->si_atmarp.sa_cha); + ATM_ADDR_COPY(&aap->aa_dstatmsub, &smp->si_atmarp.sa_csa); + smp->si_atmarp.sa_key = aap->aa_key; + smp->si_atmarp.sa_oid = aap->aa_oid; + smp->si_atmarp.sa_seq = aap->aa_seq; + + /* + * Send the message to SCSP + */ + rc = atmarp_scsp_out(aap->aa_intf, (char *)smp, smp->si_len); + + UM_FREE(smp); + return(rc); +} + + +/* + * Respond to a Cache Update Indication from SCSP + * + * + * Arguments: + * aip pointer to interface control block + * smp pointer to message from SCSP + * + * Returns: + * 0 Message processed OK + * errno Reason for failure + * + */ +int +atmarp_scsp_update_in(aip, smp) + Atmarp_intf *aip; + Scsp_if_msg *smp; +{ + int accept, rc; + Atmarp *aap; + + /* + * Look up the entry + */ + ATMARP_LOOKUP(aip, smp->si_atmarp.sa_cpa.s_addr, aap); + + /* + * Whether we accept the request depends on whether we + * already have an entry for it + */ + if (!aap) { + /* + * We don't have this entry--accept it + */ + accept = 1; + } else { + /* + * We do have an entry for this host--check the + * origin ID + */ + if (bcmp(&aip->ai_ip_addr.s_addr, + smp->si_atmarp.sa_oid.id, + SCSP_ATMARP_ID_LEN) == 0) { + /* + * The received entry originated with us-- + * reject it + */ + accept = 0; + } else if (bcmp(&aip->ai_ip_addr.s_addr, + aap->aa_oid.id, + SCSP_ATMARP_ID_LEN) == 0) { + /* + * We originated the entry we currently have-- + * only accept the new one if SCSP has higher + * priority than the existing entry + */ + accept = aap->aa_origin < UAO_SCSP; + } else { + /* + * Accept the entry if it is more up-to-date + * than the existing entry + */ + accept = KEY_EQUAL(&aap->aa_key, + &smp->si_atmarp.sa_key) && + OID_EQUAL(&aap->aa_oid, + &smp->si_atmarp.sa_oid) && + (aap->aa_seq < smp->si_atmarp.sa_seq); + } + } + + /* + * Add the entry to the cache, if appropriate + */ + if (accept) { + if (!aap) { + /* + * Copy info from SCSP to a new cache entry + */ + aap = (Atmarp *)UM_ALLOC(sizeof(Atmarp)); + if (!aap) + atmarp_mem_err("atmarp_scsp_update_in: sizeof(Atmarp)"); + UM_ZERO(aap, sizeof(Atmarp)); + + aap->aa_dstip = smp->si_atmarp.sa_cpa; + aap->aa_dstatm = smp->si_atmarp.sa_cha; + aap->aa_dstatmsub = smp->si_atmarp.sa_csa; + aap->aa_key = smp->si_atmarp.sa_key; + aap->aa_oid = smp->si_atmarp.sa_oid; + aap->aa_seq = smp->si_atmarp.sa_seq; + aap->aa_intf = aip; + aap->aa_origin = UAO_SCSP; + + /* + * Add the new entry to our cache + */ + ATMARP_ADD(aip, aap); + } else { + /* + * Update the existing entry + */ + aap->aa_dstip = smp->si_atmarp.sa_cpa; + aap->aa_dstatm = smp->si_atmarp.sa_cha; + aap->aa_dstatmsub = smp->si_atmarp.sa_csa; + aap->aa_key = smp->si_atmarp.sa_key; + aap->aa_oid = smp->si_atmarp.sa_oid; + aap->aa_seq = smp->si_atmarp.sa_seq; + aap->aa_origin = UAO_SCSP; + } + + /* + * Send the updated entry to the kernel + */ + if (atmarp_update_kernel(aap) == 0) + rc = SCSP_RSP_OK; + else + rc = SCSP_RSP_REJ; + } else { + rc = SCSP_RSP_REJ; + } + + /* + * Turn the received message into a response + */ + smp->si_type = SCSP_UPDATE_RSP; + smp->si_rc = rc; + + /* + * Send the message to SCSP + */ + rc = atmarp_scsp_out(aip, (char *)smp, smp->si_len); + + return(rc); +} + + +/* + * Read and process a message from SCSP + * + * + * Arguments: + * aip interface for read + * + * Returns: + * 0 success + * errno reason for failure + * + */ +int +atmarp_scsp_read(aip) + Atmarp_intf *aip; +{ + int len, rc; + char *buff = (char *)0; + Scsp_if_msg *smp; + Scsp_if_msg_hdr msg_hdr; + + /* + * Read the header of the message from SCSP + */ + len = read(aip->ai_scsp_sock, (char *)&msg_hdr, + sizeof(msg_hdr)); + if (len == -1) { + rc = errno; + goto read_fail; + } else if (len != sizeof(msg_hdr)) { + rc = EMSGSIZE; + goto read_fail; + } + + /* + * Get a buffer that will hold the message + */ + buff = UM_ALLOC(msg_hdr.sh_len); + if (!buff) + atmarp_mem_err("atmarp_scsp_read: msg_hdr.sh_len"); + UM_COPY(&msg_hdr, buff, sizeof(msg_hdr)); + + /* + * Read the rest of the message, if there is more than + * just a header + */ + len = msg_hdr.sh_len - sizeof(msg_hdr); + if (len > 0) { + len = read(aip->ai_scsp_sock, buff + sizeof(msg_hdr), + len); + if (len == -1) { + rc = errno; + goto read_fail; + } else if (len != msg_hdr.sh_len - sizeof(msg_hdr)) { + rc = EMSGSIZE; + goto read_fail; + } + } + + /* + * Handle the message based on its type + */ + smp = (Scsp_if_msg *)buff; + switch(smp->si_type) { + case SCSP_CFG_RSP: + if (smp->si_rc != SCSP_RSP_OK) { + goto read_fail; + } + break; + case SCSP_CACHE_IND: + rc = atmarp_scsp_cache(aip, smp); + break; + case SCSP_SOLICIT_IND: + rc = atmarp_scsp_solicit(aip, smp); + break; + case SCSP_UPDATE_IND: + rc = atmarp_scsp_update_in(aip, smp); + break; + case SCSP_UPDATE_RSP: + /* + * Ignore Update Responses + */ + rc = 0; + break; + default: + atmarp_log(LOG_ERR, "Unexpected SCSP message received"); + return(EOPNOTSUPP); + } + + UM_FREE(buff); + return(rc); + +read_fail: + if (buff) { + UM_FREE(buff); + } + + /* + * Error on socket to SCSP--close the socket and set the state + * so that we know to retry when the cache timer fires. + */ + atmarp_scsp_close(aip); + + return(rc); +} + + +/* + * Send a message to SCSP + * + * + * Arguments: + * aip pointer to ATMARP interface to send message on + * buff pointer to message buffer + * len length of message + * + * Returns: + * 0 message sent + * errno reason for failure + * + */ +int +atmarp_scsp_out(aip, buff, len) + Atmarp_intf *aip; + char *buff; + int len; +{ + int rc; + + /* + * Send the message to SCSP + */ + rc = write(aip->ai_scsp_sock, buff, len); + if (rc == len) + return(0); + + /* + * Error on write--close the socket to SCSP, clean up and + * set the state so that we know to retry when the cache + * timer fires. + */ + atmarp_scsp_close(aip); + + /* + * Set the return code + */ + if (rc < 0) { + rc = errno; + } else { + rc = EFAULT; + } + + return(rc); +} + + +/* + * Set up a socket and connect to SCSP + * + * Arguments: + * aip pointer to interface block + * + * Returns: + * 0 success, ai_scsp_sock is set + * errno reason for failure + * + * + */ +int +atmarp_scsp_connect(aip) + Atmarp_intf *aip; +{ + int len, rc, sd; + char *sn; + Scsp_if_msg cfg_msg; + + static struct sockaddr local_addr = { +#if (defined(BSD) && (BSD >= 199103)) + sizeof(struct sockaddr), /* sa_len */ +#endif + AF_UNIX, /* sa_family */ + ATMARP_SOCK_PREFIX /* sa_data */ + }; + static struct sockaddr scsp_addr = { +#if (defined(BSD) && (BSD >= 199103)) + sizeof(struct sockaddr), /* sa_len */ +#endif + AF_UNIX, /* sa_family */ + SCSPD_SOCK_NAME /* sa_data */ + }; + + /* + * Construct a name for the socket + */ + strncpy(local_addr.sa_data, ATMARP_SOCK_PREFIX, + sizeof(local_addr.sa_data)); + (void)strncat(local_addr.sa_data, aip->ai_intf, + sizeof(local_addr.sa_data)); + sn = strdup(local_addr.sa_data); + if (!sn) + atmarp_mem_err("atmarp_scsp_connect: strdup"); + + /* + * Clean up any old socket + */ + rc = unlink(sn); + if (rc < 0 && errno != ENOENT) + return(errno); + + /* + * Open a socket to SCSP + */ + sd = socket(PF_UNIX, SOCK_STREAM, 0); + if (sd == -1) { + UM_FREE(sn); + return(errno); + } + if (sd > atmarp_max_socket) { + atmarp_max_socket = sd; + } + + /* + * Set non-blocking I/O + */ +#ifdef sun + rc = fcntl(sd, F_SETFL, FNBIO + FNDELAY); +#else + rc = fcntl(sd, F_SETFL, O_NONBLOCK); +#endif + if (rc == -1) { + rc = errno; + goto scsp_connect_fail; + } + + /* + * Bind the local socket address + */ + rc = bind(sd, &local_addr, sizeof(local_addr)); + if (rc) { + rc = errno; + goto scsp_connect_fail; + } + + /* + * Connect to SCSP + */ + rc = connect(sd, &scsp_addr, sizeof(scsp_addr)); + if (rc) { + rc = errno; + goto scsp_connect_fail; + } + + /* + * Save socket information in interface control block + */ + aip->ai_scsp_sock = sd; + aip->ai_scsp_sockname = sn; + aip->ai_state = AI_STATE_UP; + + /* + * Send configuration information to SCSP + */ + UM_ZERO(&cfg_msg, sizeof(cfg_msg)); + cfg_msg.si_type = SCSP_CFG_REQ; + cfg_msg.si_proto = SCSP_PROTO_ATMARP; + strcpy(cfg_msg.si_cfg.atmarp_netif, aip->ai_intf); + len =sizeof(Scsp_if_msg_hdr) + strlen(aip->ai_intf) + 1; + cfg_msg.si_len = len; + rc = atmarp_scsp_out(aip, (char *)&cfg_msg, len); + if (rc) { + return(rc); + } + + return(0); + +scsp_connect_fail: + (void)close(sd); + aip->ai_scsp_sock = -1; + UM_FREE(sn); + aip->ai_scsp_sockname = NULL; + aip->ai_state = AI_STATE_NULL; + return(rc); +} + + +/* + * Close a socket connection to SCSP + * + * Arguments: + * aip pointer to interface block for connection to be closed + * + * Returns: + * none + * + * + */ +void +atmarp_scsp_close(aip) + Atmarp_intf *aip; +{ + /* + * Close and unlink the SCSP socket + */ + (void)close(aip->ai_scsp_sock); + aip->ai_scsp_sock = -1; + (void)unlink(aip->ai_scsp_sockname); + UM_FREE(aip->ai_scsp_sockname); + aip->ai_scsp_sockname = NULL; + + aip->ai_state = AI_STATE_NULL; + + return; +} + + +/* + * Disconnect an interface from SCSP + * + * Arguments: + * aip pointer to interface block for connection to be closed + * + * Returns: + * 0 success, ai_scsp_sock is set + * errno reason for failure + * + * + */ +int +atmarp_scsp_disconnect(aip) + Atmarp_intf *aip; +{ + int i; + Atmarp *aap; + + /* + * Close and unlink the SCSP socket + */ + atmarp_scsp_close(aip); + + /* + * Free the ATMARP cache associated with the interface + */ + for (i = 0; i < ATMARP_HASHSIZ; i++) { + for (aap = aip->ai_arptbl[i]; aap; aap = aap->aa_next) { + UM_FREE(aap); + } + aip->ai_arptbl[i] = (Atmarp *)0; + } + + return(0); +} diff --git a/usr.sbin/atm/atmarpd/atmarp_subr.c b/usr.sbin/atm/atmarpd/atmarp_subr.c new file mode 100644 index 0000000..3cc20e0 --- /dev/null +++ b/usr.sbin/atm/atmarpd/atmarp_subr.c @@ -0,0 +1,962 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atmarp_subr.c,v 1.6 1998/08/13 20:11:11 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP-ATMARP server interface: misc. subroutines + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: atmarp_subr.c,v 1.6 1998/08/13 20:11:11 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <sys/socket.h> +#include <sys/sockio.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sigmgr.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> +#include <netatm/uni/unisig_var.h> +#include <netatm/uni/uniip_var.h> + +#include <libatm.h> +#include "../scspd/scsp_msg.h" +#include "../scspd/scsp_if.h" +#include "../scspd/scsp_var.h" +#include "atmarp_var.h" + + +/* + * Find an ATMARP interface, given its socket number + * + * Arguments: + * sd socket descriptor + * + * Returns: + * 0 failure + * else pointer to interface associated with socket + * + */ +Atmarp_intf * +atmarp_find_intf_sock(sd) + int sd; +{ + Atmarp_intf *aip; + + /* + * Loop through the list of interfaces + */ + for (aip = atmarp_intf_head; aip; aip = aip->ai_next) { + if (aip->ai_scsp_sock == sd) + break; + } + + return(aip); +} + + +/* + * Find an ATMARP interface, given its name + * + * Arguments: + * name pointer to network interface name + * + * Returns: + * 0 failure + * else pointer to interface associated with name + * + */ +Atmarp_intf * +atmarp_find_intf_name(name) + char *name; +{ + Atmarp_intf *aip; + + /* + * Loop through the list of interfaces + */ + for (aip = atmarp_intf_head; aip; aip = aip->ai_next) { + if (strcmp(name, aip->ai_intf) == 0) + break; + } + + return(aip); +} + + +/* + * Clear the mark field on all ATMARP cache entries + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +atmarp_clear_marks() + +{ + int i; + Atmarp_intf *aip; + Atmarp *aap; + + /* + * Loop through list of interfaces + */ + for (aip = atmarp_intf_head; aip; aip = aip->ai_next) { + /* + * Clear mark on every entry in the interface's cache + */ + for (i = 0; i < ATMARP_HASHSIZ; i++ ) { + for (aap = aip->ai_arptbl[i]; aap; + aap = aap->aa_next) { + aap->aa_mark = 0; + } + } + } +} + + +/* + * Check whether the host system is an ATMARP server for + * the LIS associated with a given interface + * + * Arguments: + * aip pointer to an ATMARP interface control block + * + * Returns: + * 1 host is a server + * 0 host is not a server + * + */ +int +atmarp_is_server(aip) + Atmarp_intf *aip; +{ + int rc; + int buf_len = sizeof(struct air_asrv_rsp); + struct atminfreq air; + struct air_asrv_rsp *asrv_info; + + /* + * Get interface information from the kernel + */ + strcpy(air.air_int_intf, aip->ai_intf); + air.air_opcode = AIOCS_INF_ASV; + buf_len = do_info_ioctl(&air, buf_len); + if (buf_len < 0) + return(0); + + /* + * Check the interface's ATMARP server address + */ + asrv_info = (struct air_asrv_rsp *) air.air_buf_addr; + rc = (asrv_info->asp_addr.address_format == T_ATM_ABSENT) && + (asrv_info->asp_subaddr.address_format == + T_ATM_ABSENT); + UM_FREE(asrv_info); + return(rc); +} + + +/* + * Check whether an interface is up and ready for service + * + * Arguments: + * aip pointer to network interface block + * + * Returns: + * 0 interface not ready, errno has reason + * 1 interface is ready to go (interface block is updated) + * + */ +int +atmarp_if_ready(aip) + Atmarp_intf *aip; +{ + int i, len, mtu, rc, sel; + Atmarp *aap = (Atmarp *)0; + struct atminfreq air; + struct air_netif_rsp *netif_rsp = (struct air_netif_rsp *)0; + struct air_int_rsp *intf_rsp = (struct air_int_rsp *)0; + struct sockaddr_in *ip_addr; + struct sockaddr_in subnet_mask; + Atm_addr_nsap *anp; + + /* + * Get the IP address and physical interface name + * associated with the network interface + */ + UM_ZERO(&air, sizeof(struct atminfreq)); + air.air_opcode = AIOCS_INF_NIF; + strcpy(air.air_netif_intf, aip->ai_intf); + len = do_info_ioctl(&air, sizeof(struct air_netif_rsp)); + if (len <= 0) { + goto if_ready_fail; + } + netif_rsp = (struct air_netif_rsp *)air.air_buf_addr; + + ip_addr = (struct sockaddr_in *)&netif_rsp->anp_proto_addr; + if (ip_addr->sin_family != AF_INET || + ip_addr->sin_addr.s_addr == 0) { + errno = EAFNOSUPPORT; + goto if_ready_fail; + } + + /* + * Get the MTU for the network interface + */ + mtu = get_mtu(aip->ai_intf); + if (mtu < 0) { + goto if_ready_fail; + } + + + /* + * Get the subnet mask associated with the + * network interface + */ + rc = get_subnet_mask(aip->ai_intf, &subnet_mask); + if (rc || subnet_mask.sin_family != AF_INET) { + goto if_ready_fail; + } + + /* + * Get physical interface information + */ + UM_ZERO(&air, sizeof(struct atminfreq)); + air.air_opcode = AIOCS_INF_INT; + strcpy(air.air_int_intf, netif_rsp->anp_phy_intf); + len = do_info_ioctl(&air, sizeof(struct air_int_rsp)); + if (len <= 0) { + goto if_ready_fail; + } + intf_rsp = (struct air_int_rsp *)air.air_buf_addr; + + /* + * Check the signalling manager + */ + if (intf_rsp->anp_sig_proto != ATM_SIG_UNI30 && + intf_rsp->anp_sig_proto != ATM_SIG_UNI31 && + intf_rsp->anp_sig_proto != ATM_SIG_UNI40) { + errno = EINVAL; + goto if_ready_fail; + } + + /* + * Check the interface state + */ + if (intf_rsp->anp_sig_state != UNISIG_ACTIVE) { + errno = EINVAL; + goto if_ready_fail; + } + + /* + * Check the address format + */ + if (intf_rsp->anp_addr.address_format != T_ATM_ENDSYS_ADDR && + !(intf_rsp->anp_addr.address_format == + T_ATM_E164_ADDR && + intf_rsp->anp_subaddr.address_format == + T_ATM_ENDSYS_ADDR)) { + errno = EINVAL; + goto if_ready_fail; + } + + /* + * Find the selector byte value for the interface + */ + for (i=0; i<strlen(aip->ai_intf); i++) { + if (aip->ai_intf[i] >= '0' && + aip->ai_intf[i] <= '9') + break; + } + sel = atoi(&aip->ai_intf[i]); + + /* + * Make sure we're the server for this interface's LIS + */ + if (!atmarp_is_server(aip)) { + rc = EINVAL; + goto if_ready_fail; + } + + /* + * If we already have the interface active and the address + * hasn't changed, return + */ + if (aip->ai_state != AI_STATE_NULL && + bcmp((caddr_t) &((struct sockaddr_in *) + &netif_rsp->anp_proto_addr)->sin_addr, + (caddr_t)&aip->ai_ip_addr, + sizeof(aip->ai_ip_addr)) == 0 && + ATM_ADDR_EQUAL(&intf_rsp->anp_addr, + &aip->ai_atm_addr) && + ATM_ADDR_EQUAL(&intf_rsp->anp_subaddr, + &aip->ai_atm_subaddr)) { + return(1); + } + + /* + * Delete any existing ATMARP cache entry for this interface + */ + ATMARP_LOOKUP(aip, aip->ai_ip_addr.s_addr, aap); + if (aap) { + ATMARP_DELETE(aip, aap); + UM_FREE(aap); + } + + /* + * Update the interface entry + */ + aip->ai_ip_addr = ((struct sockaddr_in *) + &netif_rsp->anp_proto_addr)->sin_addr; + aip->ai_subnet_mask = subnet_mask.sin_addr; + aip->ai_mtu = mtu + 8; + ATM_ADDR_COPY(&intf_rsp->anp_addr, + &aip->ai_atm_addr); + ATM_ADDR_COPY(&intf_rsp->anp_subaddr, + &aip->ai_atm_subaddr); + anp = (Atm_addr_nsap *)aip->ai_atm_addr.address; + if (aip->ai_atm_addr.address_format == T_ATM_ENDSYS_ADDR) { + anp->aan_sel = sel; + } else if (aip->ai_atm_addr.address_format == + T_ATM_E164_ADDR && + aip->ai_atm_subaddr.address_format == + T_ATM_ENDSYS_ADDR) { + anp->aan_sel = sel; + } + + /* + * Get a new ATMARP cache for the interface + */ + aap = (Atmarp *)UM_ALLOC(sizeof(Atmarp)); + if (!aap) { + atmarp_mem_err("atmarp_if_ready: sizeof(Atmarp)"); + } + UM_ZERO(aap, sizeof(Atmarp)); + + /* + * Fill out the entry + */ + aap->aa_dstip = aip->ai_ip_addr; + ATM_ADDR_COPY(&intf_rsp->anp_addr, &aap->aa_dstatm); + ATM_ADDR_COPY(&intf_rsp->anp_subaddr, + &aap->aa_dstatmsub); + aap->aa_key.key_len = SCSP_ATMARP_KEY_LEN; + scsp_cache_key(&aap->aa_dstatm, &aap->aa_dstip, + SCSP_ATMARP_KEY_LEN, aap->aa_key.key); + aap->aa_oid.id_len = SCSP_ATMARP_ID_LEN; + aap->aa_seq = SCSP_CSA_SEQ_MIN; + UM_COPY(&aap->aa_dstip.s_addr, aap->aa_oid.id, + SCSP_ATMARP_ID_LEN); + aap->aa_intf = aip; + aap->aa_flags = AAF_SERVER; + aap->aa_origin = UAO_LOCAL; + + /* + * Add the entry to the cache + */ + ATMARP_ADD(aip, aap); + + /* + * Free dynamic data + */ + UM_FREE(netif_rsp); + UM_FREE(intf_rsp); + + return(1); + +if_ready_fail: + if (netif_rsp) + UM_FREE(netif_rsp); + if (intf_rsp) + UM_FREE(intf_rsp); + + return(0); +} + + +/* + * Copy an ATMARP cache entry from kernel format into an entry + * suitable for our cache + * + * Arguments: + * cp pointer to kernel entry + * + * Returns: + * pointer to a new cache entry + * 0 error + * + */ +Atmarp * +atmarp_copy_cache_entry(cp) + struct air_arp_rsp *cp; + +{ + struct sockaddr_in *ipp; + Atmarp_intf *aip; + Atmarp *aap; + + /* + * Sanity checks + */ + if (!cp) + return((Atmarp *)0); + aip = atmarp_find_intf_name(cp->aap_intf); + if (!aip) + return((Atmarp *)0); + + /* + * Get a new cache entry + */ + aap = (Atmarp *)UM_ALLOC(sizeof(Atmarp)); + if (!aap) { + errno = ENOMEM; + return((Atmarp *)0); + } + UM_ZERO(aap, sizeof(Atmarp)); + aap->aa_intf = aip; + + /* + * Copy fields from the kernel entry to the new entry + */ + ipp = (struct sockaddr_in *)&cp->aap_arp_addr; + UM_COPY(&ipp->sin_addr.s_addr, &aap->aa_dstip.s_addr, + sizeof(aap->aa_dstip.s_addr)); + ATM_ADDR_COPY(&cp->aap_addr, &aap->aa_dstatm); + ATM_ADDR_COPY(&cp->aap_subaddr, &aap->aa_dstatmsub); + if (cp->aap_origin == UAO_PERM) + aap->aa_flags |= AAF_PERM; + aap->aa_origin = cp->aap_origin; + + /* + * Set up fields for SCSP + */ + aap->aa_key.key_len = SCSP_ATMARP_KEY_LEN; + scsp_cache_key(&cp->aap_addr, &aap->aa_dstip, + SCSP_ATMARP_KEY_LEN, (char *)aap->aa_key.key); + aap->aa_oid.id_len = SCSP_ATMARP_ID_LEN; + UM_COPY(&aip->ai_ip_addr.s_addr, aap->aa_oid.id, + SCSP_ATMARP_ID_LEN); + aap->aa_seq = SCSP_CSA_SEQ_MIN; + + return(aap); +} + + +/* + * Send an updated ATMARP cache entry to the kernel + * + * Arguments: + * aap pointer to updated entry + * + * Returns: + * 0 success + * errno reason for failure + * + */ +int +atmarp_update_kernel(aap) + Atmarp *aap; +{ + int rc = 0, sd; + struct atmaddreq aar; + struct sockaddr_in *ipp; + + /* + * Build ioctl request + */ + UM_ZERO(&aar, sizeof(aar)); + aar.aar_opcode = AIOCS_ADD_ARP; + strncpy(aar.aar_arp_intf, aap->aa_intf->ai_intf, + sizeof(aar.aar_arp_intf)); + aar.aar_arp_origin = UAO_SCSP; + ATM_ADDR_COPY(&aap->aa_dstatm, &aar.aar_arp_addr); + ipp = (struct sockaddr_in *)&aar.aar_arp_dst; + ipp->sin_family = AF_INET; +#if (defined(BSD) && (BSD >= 199103)) + ipp->sin_len = sizeof(struct sockaddr_in); +#endif + ipp->sin_addr = aap->aa_dstip; + + /* + * Pass the new mapping to the kernel + */ + sd = socket(AF_ATM, SOCK_DGRAM, 0); + if (sd < 0) { + return(errno); + } + if (ioctl(sd, AIOCADD, (caddr_t)&aar) < 0) { + rc = errno; + } + + (void)close(sd); + return(rc); +} + + +/* + * Read the ATMARP cache from the kernel and scan it, processing + * all entries + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +atmarp_get_updated_cache() +{ + int i, len, rc; + struct atminfreq air; + struct air_arp_rsp *cp; + struct sockaddr_in *ipp; + Atmarp_intf *aip; + Atmarp *aap; + + /* + * Set up the request + */ + air.air_opcode = AIOCS_INF_ARP; + air.air_arp_flags = ARP_RESET_REF; + ipp = (struct sockaddr_in *)&air.air_arp_addr; +#if (defined(BSD) && (BSD >= 199103)) + ipp->sin_len = sizeof(struct sockaddr_in); +#endif + ipp->sin_family = AF_INET; + ipp->sin_addr.s_addr = INADDR_ANY; + + /* + * Issue an ATMARP information request IOCTL + */ + len = do_info_ioctl(&air, sizeof(struct air_arp_rsp) * 200); + if (len < 0) { + return; + } + + /* + * Clear marks on all our cache entries + */ + atmarp_clear_marks(); + + /* + * Loop through the cache, processing each entry + */ + for (cp = (struct air_arp_rsp *) air.air_buf_addr; + len > 0; + cp++, len -= sizeof(struct air_arp_rsp)) { + atmarp_process_cache_entry(cp); + } + + /* + * Now delete any old entries that aren't in the kernel's + * cache any more + */ + for (aip = atmarp_intf_head; aip; aip = aip->ai_next) { + for (i = 0; i < ATMARP_HASHSIZ; i++) { + for (aap = aip->ai_arptbl[i]; aap; + aap = aap->aa_next) { + /* + * Don't delete the entry for the server + */ + if (aap->aa_flags & AAF_SERVER) + continue; + /* + * Delete any entry that isn't marked + */ + if (!aap->aa_mark) { + rc = atmarp_scsp_update(aap, + SCSP_ASTATE_DEL); + if (rc == 0) + ATMARP_DELETE(aip, aap); + } + } + } + } + + /* + * Free the ioctl response + */ + UM_FREE(air.air_buf_addr); +} + + +/* + * Process an ATMARP cache entry from the kernel. If we already + * have the entry in our local cache, update it, otherwise, add + * it. In either case, mark our local copy so we know it's still + * in the kernel's cache. + * + * Arguments: + * cp pointer to kernel's cache entry + * + * Returns: + * none + * + */ +void +atmarp_process_cache_entry(cp) + struct air_arp_rsp *cp; + +{ + int rc; + struct sockaddr_in *ipp = (struct sockaddr_in *)&cp->aap_arp_addr; + Atmarp_intf *aip; + Atmarp *aap; + + /* + * See whether the entry is for an interface that's + * both configured and up + */ + aip = atmarp_find_intf_name(cp->aap_intf); + if (!aip || aip->ai_state != AI_STATE_UP) + return; + + /* + * Make sure the entry is valid + */ + if (!(cp->aap_flags & ARPF_VALID)) + return; + + /* + * See whether we have the entry in our cache already + */ + ATMARP_LOOKUP(aip, ipp->sin_addr.s_addr, aap); + if (aap) { + /* + * We already have this in our cache--update it + */ + aap->aa_mark = 1; + if ((cp->aap_flags & ARPF_REFRESH) && + cp->aap_origin != UAO_SCSP) { + aap->aa_seq++; + rc = atmarp_scsp_update(aap, SCSP_ASTATE_UPD); + } + } else { + /* + * This is a new entry--add it to the cache + */ + aap = atmarp_copy_cache_entry(cp); + if (!aap) + return; + ATMARP_ADD(aip, aap); + aap->aa_mark = 1; + rc = atmarp_scsp_update(aap, SCSP_ASTATE_NEW); + } + + return; +} + + +/* + * Print an SCSP ID + * + * Arguments: + * df pointer to a FILE for the dump + * ip pointer to the SCSP ID to print + * + * Returns: + * None + * + */ +static void +print_scsp_id(df, ip) + FILE *df; + Scsp_id *ip; +{ + int i; + + fprintf(df, "\t next: 0x%0x\n", (u_long)ip->next); + fprintf(df, "\t id_len: %d\n", ip->id_len); + fprintf(df, "\t id: 0x"); + for (i = 0; i < ip->id_len; i++) { + fprintf(df, "%0x ", ip->id[i]); + } + fprintf(df, "\n"); +} + + +/* + * Print an SCSP cacke key + * + * Arguments: + * df pointer to a FILE for the dump + * cp pointer to the cacke key to print + * + * Returns: + * None + * + */ +static void +print_scsp_cache_key(df, cp) + FILE *df; + Scsp_ckey *cp; +{ + int i; + + fprintf(df, "\t key_len: %d\n", cp->key_len); + fprintf(df, "\t key: 0x"); + for (i = 0; i < cp->key_len; i++) { + fprintf(df, "%0x ", cp->key[i]); + } + fprintf(df, "\n"); +} + + +/* + * Print an ATMARP interface entry + * + * Arguments: + * df pointer to a FILE for the dump + * aip pointer to interface entry + * + * Returns: + * None + * + */ +void +print_atmarp_intf(df, aip) + FILE *df; + Atmarp_intf *aip; +{ + if (!aip) { + fprintf(df, "print_atmarp_intf: NULL interface entry address\n"); + return; + } + + fprintf(df, "ATMARP network interface entry at 0x%0x\n", + (u_long)aip); + fprintf(df, "\tai_next: 0x%0x\n", + (u_long)aip->ai_next); + fprintf(df, "\tai_intf: %s\n", aip->ai_intf); + fprintf(df, "\tai_ip_addr: %s\n", + format_ip_addr(&aip->ai_ip_addr)); + fprintf(df, "\tai_subnet_mask: %s\n", + inet_ntoa(aip->ai_subnet_mask)); + fprintf(df, "\tai_mtu: %d\n", aip->ai_mtu); + fprintf(df, "\tai_atm_addr: %s\n", + format_atm_addr(&aip->ai_atm_addr)); + fprintf(df, "\tai_atm_subaddr: %s\n", + format_atm_addr(&aip->ai_atm_subaddr)); + fprintf(df, "\tai_scsp_sock: %d\n", aip->ai_scsp_sock); + fprintf(df, "\tai_scsp_sockname: %s\n", aip->ai_scsp_sockname); + fprintf(df, "\tai_state: %d\n", aip->ai_state); + fprintf(df, "\tai_mark: %d\n", aip->ai_mark); +} + + +/* + * Print an ATMARP cache entry + * + * Arguments: + * df pointer to a FILE for the dump + * aap pointer to cache entry + * + * Returns: + * None + * + */ +void +print_atmarp_cache(df, aap) + FILE *df; + Atmarp *aap; +{ + if (!aap) { + fprintf(df, "print_atmarp_cache: NULL ATMARP entry address\n"); + return; + } + + fprintf(df, "ATMARP entry at 0x%0x\n", (u_long)aap); + fprintf(df, "\taa_next: 0x%0x\n", (u_long)aap->aa_next); + fprintf(df, "\taa_dstip: %s\n", inet_ntoa(aap->aa_dstip)); + fprintf(df, "\taa_dstatm: %s\n", + format_atm_addr(&aap->aa_dstatm)); + fprintf(df, "\taa_dstatmsub: %s\n", + format_atm_addr(&aap->aa_dstatmsub)); + fprintf(df, "\taa_key:\n"); + print_scsp_cache_key(df, &aap->aa_key); + fprintf(df, "\taa_oid:\n"); + print_scsp_id(df, &aap->aa_oid); + fprintf(df, "\taa_seq: %d (0x%x)\n", aap->aa_seq, + aap->aa_seq); + fprintf(df, "\taa_intf: 0x%0x\n", (u_long)aap->aa_intf); + fprintf(df, "\taa_flags: "); + if (aap->aa_flags & AAF_PERM) + fprintf(df, "Permanent "); + if (aap->aa_flags & AAF_SERVER) + fprintf(df, "Server "); + fprintf(df, "\n"); + fprintf(df, "\taa_origin: %d\n", aap->aa_origin); + fprintf(df, "\taa_mark: %d\n", aap->aa_mark); +} + + +/* + * Print the entire ATMARP cache + * + * Arguments: + * df pointer to a FILE for the dump + * aip pointer to interface whose cache is to be printed + * + * Returns: + * None + * + */ +void +dump_atmarp_cache(df, aip) + FILE *df; + Atmarp_intf *aip; +{ + int i; + Atmarp *aap; + + if (!aip) { + fprintf(df, "dump_atmarp_cache: NULL interface address\n"); + return; + } + + fprintf(df, "ATMARP cache for interface %s\n", aip->ai_intf); + for (i=0; i<ATMARP_HASHSIZ; i++) { + for (aap=aip->ai_arptbl[i]; aap; aap=aap->aa_next) { + print_atmarp_cache(df, aap); + } + } +} + + +#ifdef NOTDEF +/* + * Print an ATMARP super-LIS entry + * + * Arguments: + * df pointer to a FILE for the dump + * asp pointer to super-LIS entry to be printed + * + * Returns: + * None + * + */ +void +print_atmarp_slis(df, asp) + FILE *df; + Atmarp_slis *asp; +{ + Atmarp_intf **aipp; + + if (!asp) { + fprintf(df, "print_atmarp_slis: NULL SLIS address\n"); + return; + } + + fprintf(df, "SLIS entry at 0x%0x\n", (u_long)asp); + fprintf(df, "\tas_next: 0x%0x\n", (u_long)asp->as_next); + fprintf(df, "\tas_name: %s\n", asp->as_name); + fprintf(df, "\tas_cnt: %d\n", asp->as_cnt); + for (aipp = &asp->as_intfs; *aipp; aipp++) { + fprintf(df, "\t%s (%s)\n", (*aipp)->ai_name, + (*aipp)->ai_intf); + } +} +#endif + + +/* + * Dump ATMARPD information + * + * Called as the result of a SIGINT signal. + * + * Arguments: + * sig signal number + * + * Returns: + * None + * + */ +void +atmarp_sigint(sig) + int sig; +{ + Atmarp_intf *aip; + FILE *df; + char fname[64]; + static int dump_no = 0; + + /* + * Build a file name + */ + UM_ZERO(fname, sizeof(fname)); + sprintf(fname, "/tmp/atmarpd.%d.%03d.out", getpid(), dump_no++); + + /* + * Open the output file + */ + df = fopen(fname, "w"); + if (df == (FILE *)0) + return; + + /* + * Dump the interface control blocks and + * associated ATMARP caches + */ + for (aip = atmarp_intf_head; aip; aip = aip->ai_next) { + print_atmarp_intf(df, aip); + fprintf(df, "\n"); + dump_atmarp_cache(df, aip); + fprintf(df, "\n"); + } + + /* + * Close the output file + */ + (void)fclose(df); +} diff --git a/usr.sbin/atm/atmarpd/atmarp_timer.c b/usr.sbin/atm/atmarpd/atmarp_timer.c new file mode 100644 index 0000000..f9c41cc --- /dev/null +++ b/usr.sbin/atm/atmarpd/atmarp_timer.c @@ -0,0 +1,223 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atmarp_timer.c,v 1.2 1998/08/13 20:11:12 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP-ATMARP server interface: timer routines + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atmarp_timer.c,v 1.2 1998/08/13 20:11:12 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "../scspd/scsp_msg.h" +#include "../scspd/scsp_if.h" +#include "../scspd/scsp_var.h" +#include "atmarp_var.h" + + +/* + * Cache update timeout processing + * + * When the cache update timer fires, we read the cache from the + * kernel, update the internal cache, and restart the timer. + * + * Arguments: + * tp pointer to a HARP timer block + * + * Returns: + * None + * + */ +void +atmarp_cache_timeout(tp) + Harp_timer *tp; +{ + Atmarp_intf *aip; + + /* + * Verify the status of all configured interfaces + */ + for (aip = atmarp_intf_head; aip; aip = aip->ai_next) { + if (atmarp_if_ready(aip)) { + /* + * The interface is up but we don't have + * a connection to SCSP--make a connection + */ + if (aip->ai_state == AI_STATE_NULL) + (void)atmarp_scsp_connect(aip); + } else { + /* + * The interface is down--disconnect from SCSP + */ + if (aip->ai_state != AI_STATE_NULL) + (void)atmarp_scsp_disconnect(aip); + } + } + + /* + * Read the cache from the kernel + */ + atmarp_get_updated_cache(); + + /* + * Restart the cache update timer + */ + HARP_TIMER(tp, ATMARP_CACHE_INTERVAL, atmarp_cache_timeout); +} + + +/* + * Permanent cache entry timer processing + * + * Permanent cache entries (entries that are administratively added + * and the entry for the server itself) don't ever get refreshed, so + * we broadcast updates for them every 10 minutes so they won't get + * deleted from the remote servers' caches + * + * Arguments: + * tp pointer to a HARP timer block + * + * Returns: + * None + * + */ +void +atmarp_perm_timeout(tp) + Harp_timer *tp; +{ + int i, rc; + Atmarp_intf *aip; + Atmarp *aap; + + /* + * Loop through all interfaces + */ + for (aip = atmarp_intf_head; aip; aip = aip->ai_next) { + /* + * Loop through the interface's cache + */ + for (i = 0; i < ATMARP_HASHSIZ; i++) { + for (aap = aip->ai_arptbl[i]; aap; + aap = aap->aa_next) { + /* + * Find and update permanent entries + */ + if ((aap->aa_flags & (AAF_PERM | + AAF_SERVER)) != 0) { + aap->aa_seq++; + rc = atmarp_scsp_update(aap, + SCSP_ASTATE_UPD); + } + } + } + } + + /* + * Restart the permanent cache entry timer + */ + HARP_TIMER(tp, ATMARP_PERM_INTERVAL, atmarp_perm_timeout); +} + + +/* + * Keepalive timeout processing + * + * When the keepalive timer fires, we send a NOP to SCSP. This + * will help us detect a broken connection. + * + * Arguments: + * tp pointer to a HARP timer block + * + * Returns: + * None + * + */ +void +atmarp_keepalive_timeout(tp) + Harp_timer *tp; +{ + Atmarp_intf *aip; + Scsp_if_msg *msg; + + /* + * Back off to start of DCS entry + */ + aip = (Atmarp_intf *) ((caddr_t)tp - + (int)(&((Atmarp_intf *)0)->ai_keepalive_t)); + + /* + * Get a message buffer + */ + msg = (Scsp_if_msg *)UM_ALLOC(sizeof(Scsp_if_msg)); + if (!msg) { + } + UM_ZERO(msg, sizeof(Scsp_if_msg)); + + /* + * Build a NOP message + */ + msg->si_type = SCSP_NOP_REQ; + msg->si_proto = SCSP_PROTO_ATMARP; + msg->si_len = sizeof(Scsp_if_msg_hdr); + + /* + * Send the message to SCSP + */ + (void)atmarp_scsp_out(aip, (char *)msg, msg->si_len); + UM_FREE(msg); + + /* + * Restart the keepalive timer + */ + HARP_TIMER(&aip->ai_keepalive_t, ATMARP_KEEPALIVE_INTERVAL, + atmarp_keepalive_timeout); +} diff --git a/usr.sbin/atm/atmarpd/atmarp_var.h b/usr.sbin/atm/atmarpd/atmarp_var.h new file mode 100644 index 0000000..e8dfa4b --- /dev/null +++ b/usr.sbin/atm/atmarpd/atmarp_var.h @@ -0,0 +1,224 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atmarp_var.h,v 1.6 1998/08/13 20:11:12 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP-ATMARP server interface: control blocks + * + */ + +#ifndef _ATMARP_ATMARP_VAR_H +#define _ATMARP_ATMARP_VAR_H + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +/* + * Operational constants + */ +#define ATMARP_DIR "/tmp" +#define ATMARP_SOCK_PREFIX "AA_" +#define ATMARP_CACHE_INTERVAL 50 +#define ATMARP_PERM_INTERVAL 600 +#define ATMARP_KEEPALIVE_INTERVAL 5 + + +/* + * Macros for manipulating ATMARP tables and entries + */ +#define ATMARP_HASHSIZ 19 /* Hash table size */ + +#define ATMARP_HASH(ip) ((u_long)(ip) % ATMARP_HASHSIZ) + +#define ATMARP_ADD(ai, aa) \ +{ \ + Atmarp **h; \ + h = &ai->ai_arptbl[ATMARP_HASH((aa)->aa_dstip.s_addr)]; \ + LINK2TAIL((aa), Atmarp, *h, aa_next); \ +} + +#define ATMARP_DELETE(ai, aa) \ +{ \ + Atmarp **h; \ + h = &ai->ai_arptbl[ATMARP_HASH((aa)->aa_dstip.s_addr)]; \ + UNLINK((aa), Atmarp, *h, aa_next); \ +} + +#define ATMARP_LOOKUP(ai, ip, aa) \ +{ \ + for ((aa) = (ai)->ai_arptbl[ATMARP_HASH(ip)]; \ + (aa); (aa) = (aa)->aa_next) { \ + if ((aa)->aa_dstip.s_addr == (ip)) \ + break; \ + } \ +} + + +/* + * Macro to compare originator ID structures + */ +#define OID_EQUAL(id1, id2) \ + (((id1)->id_len == (id2)->id_len) && \ + (bcmp((caddr_t)(id1)->id, \ + (caddr_t)(id2)->id, \ + (id1)->id_len) == 0)) + +#define KEY_EQUAL(key1, key2) \ + (((key1)->key_len == (key2)->key_len) && \ + (bcmp((caddr_t)(key1)->key, \ + (caddr_t)(key2)->key, \ + (key1)->key_len) == 0)) + + +/* + * Interface entry for ATMARP SCSP interface daemon + */ +struct atmarp_intf { + struct atmarp_intf *ai_next; /* Next chained I/F */ + char ai_intf[IFNAMSIZ]; /* Network I/F name */ + struct in_addr ai_ip_addr; /* IP address */ + struct in_addr ai_subnet_mask; /* Subnet mask */ + int ai_mtu; /* IP MTU */ + Atm_addr ai_atm_addr; /* ATM address */ + Atm_addr ai_atm_subaddr; /* ATM subaddress */ + int ai_scsp_sock; /* Socket to SCSP */ + Harp_timer ai_keepalive_t; /* Keepalive timer */ + char *ai_scsp_sockname; /* Socket name */ + u_char ai_state; /* Interface state */ + u_char ai_mark; + struct atmarp *ai_arptbl[ATMARP_HASHSIZ]; /* ARP cache */ +}; +typedef struct atmarp_intf Atmarp_intf; + +#define AI_STATE_NULL 0 +#define AI_STATE_UP 1 + + +/* + * Super-LIS control block for ATMARP server daemon + */ +struct atmarp_slis { + struct atmarp_slis *as_next; /* Next super-LIS */ + char *as_name; /* Name of super-LIS */ + int as_cnt; /* LIS count */ + Atmarp_intf *as_intfs; /* List of intfs */ +}; +typedef struct atmarp_slis Atmarp_slis; + + +/* + * ATMARP cache entry format + */ +struct atmarp { + struct atmarp *aa_next; /* Hash chain link */ + struct in_addr aa_dstip; /* Destination IP addr */ + Atm_addr aa_dstatm; /* Destination ATM addr */ + Atm_addr aa_dstatmsub; /* Destination ATM subaddr */ + struct scsp_ckey aa_key; /* SCSP cache key */ + struct scsp_id aa_oid; /* SCSP originator ID */ + long aa_seq; /* SCSP sequence no. */ + Atmarp_intf *aa_intf; /* Interface for entry */ + u_char aa_flags; /* Flags (see below) */ + u_char aa_origin; /* Entry origin */ + char aa_mark; /* Mark */ +}; +typedef struct atmarp Atmarp; + +/* + * ATMARP Entry Flags + */ +#define AAF_PERM 0x01 /* Entry is permanent */ +#define AAF_SERVER 0x02 /* Entry is for the server */ + + +/* + * Global variables + */ +extern char *prog; +extern int atmarp_debug_mode; +extern int atmarp_max_socket; +extern Atmarp_intf *atmarp_intf_head; +extern Atmarp_slis *atmarp_slis_head; +extern FILE *atmarp_log_file; + + +/* + * Function definitions + */ + +/* atmarp_config.c */ +extern int atmarp_cfg_netif __P((char *)); + +/* atmarp_log.c */ +#if __STDC__ +extern void atmarp_log __P((const int, const char *, ...)); +#else +extern void atmarp_log __P((int, char *, va_alist)); +#endif +extern void atmarp_mem_err __P((char *)); + +/* atmarp_scsp.c */ +extern int atmarp_scsp_cache __P((Atmarp_intf *, Scsp_if_msg *)); +extern int atmarp_scsp_update __P((Atmarp *, int)); +extern int atmarp_scsp_update_in __P((Atmarp_intf *, + Scsp_if_msg *)); +extern int atmarp_scsp_read __P((Atmarp_intf *)); +extern int atmarp_scsp_out __P((Atmarp_intf *, char *, int)); +extern int atmarp_scsp_connect __P((Atmarp_intf *)); +extern void atmarp_scsp_close __P((Atmarp_intf *)); +extern int atmarp_scsp_disconnect __P((Atmarp_intf *)); + +/* atmarp_subr.c */ +extern Atmarp_intf *atmarp_find_intf_sock __P((int)); +extern Atmarp_intf *atmarp_find_intf_name __P((char *)); +extern void atmarp_clear_marks __P(()); +extern int atmarp_is_server __P((Atmarp_intf *)); +extern int atmarp_if_ready __P((Atmarp_intf *)); +extern Atmarp * atmarp_copy_cache_entry __P((struct air_arp_rsp *)); +extern void atmarp_get_updated_cache __P(()); +extern void atmarp_process_cache_entry __P((struct air_arp_rsp *)); +extern void print_atmarp_intf __P((FILE *, Atmarp_intf *)); +extern void print_atmarp_cache __P((FILE *, Atmarp *)); +extern void dump_atmarp_cache __P((FILE *, Atmarp_intf *)); +extern void atmarp_sigint __P((int)); + +/* atmarp_timer.c */ +extern void atmarp_cache_timeout __P((Harp_timer *)); +extern void atmarp_perm_timeout __P((Harp_timer *)); +extern void atmarp_keepalive_timeout __P((Harp_timer *)); + + +#endif /* _ATMARP_ATMARP_VAR_H */ diff --git a/usr.sbin/atm/atmarpd/atmarpd.8 b/usr.sbin/atm/atmarpd/atmarpd.8 new file mode 100644 index 0000000..fe3f751 --- /dev/null +++ b/usr.sbin/atm/atmarpd/atmarpd.8 @@ -0,0 +1,129 @@ +.\" +.\" =================================== +.\" 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. +.\" +.\" @(#) $Id: atmarpd.1,v 1.2 1998/08/26 21:39:39 johnc Exp $ +.\" +.\" +.de EX \"Begin example +.ne 5 +.if n .sp 1 +.if t .sp .5 +.nf +.in +.5i +.. +.de EE +.fi +.in -.5i +.if n .sp 1 +.if t .sp .5 +.. +.TH ATMARPD 8 "1998-08-04" "HARP" + +.SH NAME +atmarpd \- ATMARP/SCSP interface daemon +.SH SYNOPSIS +.B atmarpd +[\fB-l\fP <log file>] +[\fB-d\fP] +<netif> ... + +.SH DESCRIPTION +\fIAtmarpd\fP provides an interface between the ATMARP server in the +kernel and the SCSP daemon for the Host ATM Research Platform +(HARP) networking software. +\fIAtmarpd\fP reads the ATMARP cache from the kernel periodically +and passes any updated entries to \fIscspd\fP so they will be +propagated to remote servers. +It also accepts updated entries that remote servers have sent to +\fIscspd\fP and, if they are +new or more up to date than current entries, installs them +in the kernel's ATMARP cache. +Both \fIatmarpd\fP and \fIscspd\fP must be running before any ATMARP +cache synchronization can take place. + +When \fIatmarpd\fP starts, it parses its command line and puts +itself into the background. + +The command-line options are: +.IP "\fB-l\fP <log file>" 15 +Specifies that \fIatmarpd\fP is to write log messages to the the +file named <log file> rather than to the system log. +.IP "\fB-d\fP" 15 +Specifies that \fIatmarpd\fP is to be run in debug mode. +In debug mode, \fIatmarpd\fP is not put into the background. +Log messages are written to standard output instead of to +the log file. +.IP "<netif>" 15 +Specifies the network interface(s) for which the host is providing +ATMARP service and whose caches are to be synchronized using SCSP. +If multiple network interface names are be specified, \fIatmarpd\fP +will provide an interface to \fIscspd\fP for the servers on all the +specified interfaces. + +.SH SIGNAL PROCESSING +The following signals can be used to control \fIatmarpd\fP: + +.IP \fBSIGINT\fP 10 +Dump debugging information to a file. +When it receives a SIGINT signal, \fIatmarpd\fP dumps a summary of +its control blocks to a text file (see "\fBFILES\fB"). + +.SH FILES + +.IP "/tmp/atmarpd.<pid>.<seq>.out" +Debugging information dump file name. +\fIAtmarpd\fP writes a summary of its control blocks to this file +when it receives a SIGINT signal. +<pid> is the process ID of the daemon and <seq> is a sequence +number which is incremented every time a dump is taken. + +.SH "SEE ALSO" +\fIatm\fP (8); +\fIscspd\fP (8); +RFC 1577, \fIClassical IP and ARP over ATM\fP; +RFC 2225, \fIClassical IP and ARP over ATM\fP; +RFC 2334, \fIServer Cache Synchronization Protocol (SCSP)\fP; +draft-ietf-ion-scsp-atmarpd-00.txt, \fIA Distributed ATMARP Service +Using SCSP\fP. + + +.SH BUGS +Results are unpredictable if multiple instantiations of +\fIatmarpd\fP are run simulatneously for a given network interface. + +Please report any bugs to harp-bugs@magic.net. + +.SH COPYRIGHT +Copyright (c) 1994-1998, Network Computing Services, Inc. + +.SH AUTHORS +John Cavanaugh, Network Computing Services, Inc. +.br +Mike Spengler, Network Computing Services, Inc. +.br +Joe Thomas, Network Computing Services, Inc. +.fi +.SH ACKNOWLEDGMENTS +This software was developed with the support of the Defense +Advanced Research Projects Agency (DARPA). diff --git a/usr.sbin/atm/atmarpd/atmarpd.c b/usr.sbin/atm/atmarpd/atmarpd.c new file mode 100644 index 0000000..72ebb52 --- /dev/null +++ b/usr.sbin/atm/atmarpd/atmarpd.c @@ -0,0 +1,409 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: atmarpd.c,v 1.5 1998/08/13 20:11:13 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP-ATMARP server interface: main line code + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: atmarpd.c,v 1.5 1998/08/13 20:11:13 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <sys/ttycom.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "../scspd/scsp_msg.h" +#include "../scspd/scsp_if.h" +#include "../scspd/scsp_var.h" +#include "atmarp_var.h" + + +/* + * Global variables + */ +char *prog; +int atmarp_debug_mode = 0; +int atmarp_max_socket = 0; +Atmarp_intf *atmarp_intf_head = (Atmarp_intf *)0; +Atmarp_slis *atmarp_slis_head = (Atmarp_slis *)0; +FILE *atmarp_log_file = (FILE *)0; +char *atmarp_log_file_name = (char *)0; +Harp_timer cache_timer, perm_timer; + + + +/* + * Print a usage message + * + * Arguments: + * none + * + * Returns: + * exits, does not return + * + */ +void +usage() +{ + fprintf(stderr, "usage: %s [-d] [-l <log_file>] <net_intf> ...\n", prog); + exit(1); +} + + +/* + * Process command line parameters + * + * Arguments: + * argc number of command-line arguments + * argv list of pointers to command-line arguments + * + * Returns: + * none + * + */ +static void +initialize(argc, argv) + int argc; + char *argv[]; + +{ + int i, rc; + + /* + * Save program name, ignoring any path components + */ + if (prog = (char *)strrchr(argv[0], '/')) + prog++; + else + prog = argv[0]; + + /* + * Make sure we're being invoked by the super user + */ + i = getuid(); + if (i != 0) { + fprintf(stderr, "%s: You must be root to run this program\n", + prog); + exit(1); + } + + /* + * Scan arguments, checking for options + */ + for (i = 1; i < argc; i++) { + if (argv[i][0] == '-') { + if (strcmp(argv[i], "-d") == 0) { + atmarp_debug_mode = TRUE; + } else if (strcmp(argv[i], "-l") == 0) { + i++; + if (i >= argc) { + fprintf(stderr, "%s: Log file name missing\n", + prog); + exit(1); + } + atmarp_log_file_name = argv[i]; + } else { + fprintf(stderr, "%s: Unrecognized option \"%s\"\n", + prog, argv[i]); + exit(1); + } + } else { + /* + * Parameter is a network interface name + */ + rc = atmarp_cfg_netif(argv[i]); + if (rc) { + fprintf(stderr, "%s: Error configuring network interface %s\n", + prog, argv[i]); + exit(1); + } + } + } + + /* + * Make sure we had at least one interface configured + */ + if (!atmarp_intf_head) { + usage(); + } +} + + +/* + * Daemon housekeeping + * + * Arguments: + * None + * + * Returns: + * None + * + */ +static void +start_daemon() + +{ + int dpid, fd, file_count, rc; + + /* + * Ignore selected signals + */ +#ifdef SIGTTOU + signal(SIGTTOU, SIG_IGN); +#endif +#ifdef SIGTTIN + signal(SIGTTIN, SIG_IGN); +#endif +#ifdef SIGTSTP + signal(SIGTSTP, SIG_IGN); +#endif +#ifdef SIGPIPE + signal(SIGPIPE, SIG_IGN); +#endif + + /* + * Skip putting things into the background if we're + * in debugging mode + */ + if (atmarp_debug_mode) + goto daemon_bypass; + + /* + * Set up syslog for error logging + */ + if (!atmarp_log_file) { + openlog(prog, LOG_PID | LOG_CONS, LOG_DAEMON); + } + + /* + * Put the daemon into the background + */ + dpid = fork(); + if (dpid < 0) { + atmarp_log(LOG_ERR, "fork failed"); + exit(1); + } + if (dpid > 0) { + /* + * This is the parent process--just exit and let + * the daughter do all the work + */ + exit(0); + } + + /* + * Disassociate from any controlling terminal + */ + rc = setpgrp(0, getpid()); + if (rc < 0) { + atmarp_log(LOG_ERR, "can't change process group"); + exit(1); + } + fd = open("/dev/tty", O_RDWR); + if (fd >= 0) { + ioctl(fd, TIOCNOTTY, (char *)0); + close(fd); + } + + /* + * Close all open file descriptors + */ + file_count = getdtablesize(); + for (fd=0; fd<file_count; fd++) { + close(fd); + } + + /* + * Open log file, if specified + */ + if (atmarp_log_file_name) { + atmarp_log_file = fopen(atmarp_log_file_name, "a"); + if (!atmarp_log_file) { + atmarp_log(LOG_ERR, "%s: Can't open log file \'%s\'\n", + prog, atmarp_log_file_name); + exit(1); + } + } + + /* + * Set up and start interval timer + */ +daemon_bypass: + init_timer(); + + /* + * Move to a safe directory + */ + chdir(ATMARP_DIR); + + /* + * Clear the file mode creation mask + */ + umask(0); + + + /* + * Set up signal handlers + */ + rc = (int)signal(SIGINT, atmarp_sigint); + if (rc == -1) { + atmarp_log(LOG_ERR, "SIGINT signal setup failed"); + exit(1); + } +} + + +/* + * Main line code + * + * The ATMARP server resides in the kernel, while SCSP runs as a daemon + * in user space. This program exists to provide an interface between + * the two. It periodically polls the kernel to get the ATMARP cache + * and passes information about new entries to SCSP. It also accepts + * new information from SCSP and passes it to the kernel. + * + * Arguments: + * argc number of command-line arguments + * argv list of pointers to command-line arguments + * + * Returns: + * none + * + */ +main(argc, argv) + int argc; + char *argv[]; + +{ + int i, rc; + fd_set read_set, write_set, except_set; + Atmarp_intf *aip; + + /* + * Process command line arguments + */ + initialize(argc, argv); + + /* + * Put the daemon into the background + */ + start_daemon(); + + /* + * Start the cache update timer + */ + HARP_TIMER(&cache_timer, ATMARP_CACHE_INTERVAL, + atmarp_cache_timeout); + + /* + * Start the permanent cache entry timer + */ + HARP_TIMER(&perm_timer, ATMARP_PERM_INTERVAL, + atmarp_perm_timeout); + + /* + * Establish a connection to SCSP for each interface. If a + * connect fails, it will be retried when the cache update + * timer fires. + */ + for (aip = atmarp_intf_head; aip; aip = aip->ai_next) { + if (atmarp_if_ready(aip)) { + (void)atmarp_scsp_connect(aip); + } + } + + /* + * Read the cache from the kernel + */ + atmarp_get_updated_cache(); + + /* + * Main program loop -- wait for data to come in from SCSP. + * When the timer fires, it will be handled elsewhere. + */ + while (1) { + /* + * Wait for input from SCSP + */ + FD_ZERO(&read_set); + FD_ZERO(&write_set); + FD_ZERO(&except_set); + for (aip = atmarp_intf_head; aip; aip = aip->ai_next) { + if (aip->ai_scsp_sock != -1) { + FD_SET(aip->ai_scsp_sock, &read_set); + } + } + rc = select(atmarp_max_socket + 1, + &read_set, &write_set, + &except_set, (struct timeval *)0); + if (rc < 0) { + if (harp_timer_exec) { + timer_proc(); + continue; + } else if (errno = EINTR) { + continue; + } else { + atmarp_log(LOG_ERR, "Select failed"); + abort(); + } + } + + /* + * Read and process the input from SCSP + */ + for (i = 0; i <= atmarp_max_socket; i++) { + if (FD_ISSET(i, &read_set)) { + aip = atmarp_find_intf_sock(i); + if (aip) + rc = atmarp_scsp_read(aip); + } + } + } +} diff --git a/usr.sbin/atm/scspd/Makefile b/usr.sbin/atm/scspd/Makefile new file mode 100644 index 0000000..6bd5e1e --- /dev/null +++ b/usr.sbin/atm/scspd/Makefile @@ -0,0 +1,42 @@ +# +# +# =================================== +# 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. +# +# @(#) $Id: Makefile,v 1.5 1998/07/10 16:01:58 jpt Exp $ +# +# + +PROG= scspd +SRCS= scspd.c scsp_cafsm.c scsp_config.c scsp_config_lex.c \ + scsp_config_parse.y \ + scsp_hfsm.c scsp_if.c scsp_input.c scsp_log.c scsp_msg.c \ + scsp_output.c scsp_print.c scsp_socket.c scsp_subr.c \ + scsp_timer.c +MAN8= scspd.8 + +CFLAGS+= -I ${.CURDIR}/../../../sys +LDADD+= -latm +YFLAGS= -d + +.include <bsd.prog.mk> diff --git a/usr.sbin/atm/scspd/scsp_cafsm.c b/usr.sbin/atm/scspd/scsp_cafsm.c new file mode 100644 index 0000000..b9d2b51 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_cafsm.c @@ -0,0 +1,1448 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: scsp_cafsm.c,v 1.7 1998/08/21 18:08:23 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * Cache Alignment finite state machine + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_cafsm.c,v 1.7 1998/08/21 18:08:23 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" + + +/* + * CA FSM actions + */ +#define CA_ACTION_CNT 20 +int scsp_ca_act_00 __P((Scsp_dcs *, void *)); +int scsp_ca_act_01 __P((Scsp_dcs *, void *)); +int scsp_ca_act_02 __P((Scsp_dcs *, void *)); +int scsp_ca_act_03 __P((Scsp_dcs *, void *)); +int scsp_ca_act_04 __P((Scsp_dcs *, void *)); +int scsp_ca_act_05 __P((Scsp_dcs *, void *)); +int scsp_ca_act_06 __P((Scsp_dcs *, void *)); +int scsp_ca_act_07 __P((Scsp_dcs *, void *)); +int scsp_ca_act_08 __P((Scsp_dcs *, void *)); +int scsp_ca_act_09 __P((Scsp_dcs *, void *)); +int scsp_ca_act_10 __P((Scsp_dcs *, void *)); +int scsp_ca_act_11 __P((Scsp_dcs *, void *)); +int scsp_ca_act_12 __P((Scsp_dcs *, void *)); +int scsp_ca_act_13 __P((Scsp_dcs *, void *)); +int scsp_ca_act_14 __P((Scsp_dcs *, void *)); +int scsp_ca_act_15 __P((Scsp_dcs *, void *)); +int scsp_ca_act_16 __P((Scsp_dcs *, void *)); +int scsp_ca_act_17 __P((Scsp_dcs *, void *)); +int scsp_ca_act_18 __P((Scsp_dcs *, void *)); +int scsp_ca_act_19 __P((Scsp_dcs *, void *)); + +static int (*scsp_ca_act_vec[CA_ACTION_CNT])() = { + scsp_ca_act_00, + scsp_ca_act_01, + scsp_ca_act_02, + scsp_ca_act_03, + scsp_ca_act_04, + scsp_ca_act_05, + scsp_ca_act_06, + scsp_ca_act_07, + scsp_ca_act_08, + scsp_ca_act_09, + scsp_ca_act_10, + scsp_ca_act_11, + scsp_ca_act_12, + scsp_ca_act_13, + scsp_ca_act_14, + scsp_ca_act_15, + scsp_ca_act_16, + scsp_ca_act_17, + scsp_ca_act_18, + scsp_ca_act_19 +}; + +/* + * CA FSM state table + */ +static int ca_state_table[SCSP_CAFSM_EVENT_CNT][SCSP_CAFSM_STATE_CNT] = { + /* 0 1 2 3 4 5 */ + { 1, 1, 1, 1, 1, 1 }, /* 0 */ + { 2, 2, 2, 2, 2, 2 }, /* 1 */ + { 0, 3, 4, 5, 15, 15 }, /* 2 */ + { 0, 17, 17, 17, 7, 7 }, /* 3 */ + { 0, 17, 17, 17, 8, 8 }, /* 4 */ + { 0, 17, 17, 17, 10, 10 }, /* 5 */ + { 0, 6, 6, 0, 9, 9 }, /* 6 */ + { 0, 0, 0, 0, 12, 12 }, /* 7 */ + { 0, 0, 0, 0, 13, 13 }, /* 8 */ + { 18, 14, 14, 14, 11, 11 }, /* 9 */ + { 0, 19, 0, 0, 16, 16 }, /* 10 */ +}; + + +/* + * Cache Alignment finite state machine + * + * Arguments: + * dcsp pointer to a DCS control block for the neighbor + * event the event which has occurred + * p pointer to further parameter, if there is one + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_cafsm(dcsp, event, p) + Scsp_dcs *dcsp; + int event; + void *p; +{ + int action, rc, state; + + /* + * Select an action from the state table + */ + state = dcsp->sd_ca_state; + action = ca_state_table[event][state]; + if (scsp_trace_mode & SCSP_TRACE_CAFSM) { + scsp_trace("CAFSM: state=%d, event=%d, action=%d\n", + state, event, action); + } + if (action >= CA_ACTION_CNT || action < 0) { + scsp_log(LOG_ERR, "CA FSM--invalid action state=%d, event=%d, action=%d", + state, event, action); + abort(); + } + + /* + * Perform the selected action + */ + rc = scsp_ca_act_vec[action](dcsp, p); + + return(rc); +} + + +/* + * CA finite state machine action 0 + * Unexpected action -- log an error message and go to Master/Slave + * Negotiation. The unexpected action is probably from a protocol + * error. + * + * Arguments: + * dcsp pointer to DCS control block + * p ignored + * + * Returns: + * EOPNOTSUPP always returns EOPNOTSUPP + * + */ +int +scsp_ca_act_00(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + int rc; + + /* + * Log an error message + */ + scsp_log(LOG_ERR, "CA FSM error--unexpected action, state=%d", + dcsp->sd_ca_state); + + /* + * Set the new state + */ + dcsp->sd_ca_state = SCSP_CAFSM_NEG; + + /* + * Clear out the DCS block + */ + scsp_dcs_cleanup(dcsp); + + /* + * Notify the client I/F FSM + */ + rc = scsp_cfsm(dcsp, SCSP_CIFSM_CA_DOWN, (Scsp_msg *)0, + (Scsp_if_msg *)0); + + return(rc); +} + + +/* + * CA finite state machine action 1 + * Hello FSM has reached Bidirectional state -- go to Master/Slave + * Negotiation state, make a copy of the client's cache, send first CA + * message. + * + * Arguments: + * dcsp pointer to DCS control block + * p ignored + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_ca_act_01(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + int i, rc; + Scsp_cse *csep, *dupp; + + /* + * Set the new state + */ + dcsp->sd_ca_state = SCSP_CAFSM_NEG; + + /* + * Make a copy of client's cache entries for cache alignment + */ + for (i = 0; i < SCSP_HASHSZ; i++) { + for (csep = dcsp->sd_server->ss_cache[i]; + csep; csep = csep->sc_next) { + dupp = scsp_dup_cse(csep); + LINK2TAIL(dupp, Scsp_cse, dcsp->sd_ca_csas, + sc_next); + } + } + + /* + * Select an initial sequence number + */ + dcsp->sd_ca_seq = (int)time((time_t *)0); + + /* + * Send a CA message + */ + rc = scsp_send_ca(dcsp); + if (rc == 0) { + HARP_TIMER(&dcsp->sd_ca_rexmt_t, dcsp->sd_ca_rexmt_int, + scsp_ca_retran_timeout); + } + + return(rc); +} + + +/* + * CA finite state machine action 2 + * Hello FSM has gone down -- go to Down state + * + * Arguments: + * dcsp pointer to DCS control block + * p ignored + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_ca_act_02(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + int rc; + + /* + * Set the new state + */ + dcsp->sd_ca_state = SCSP_CAFSM_DOWN; + + /* + * Clear out the DCS block + */ + scsp_dcs_cleanup(dcsp); + + /* + * Notify the client I/F FSM + */ + rc = scsp_cfsm(dcsp, SCSP_CIFSM_CA_DOWN, (Scsp_msg *)0, + (Scsp_if_msg *)0); + + return(rc); +} + + +/* + * CA finite state machine action 3 + * CA message received -- select Cache Summarize Master or Slave state + * + * Arguments: + * dcsp pointer to DCS control block + * p pointer to received message + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_ca_act_03(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + int rc = 0; + Scsp_msg *msg = (Scsp_msg *)p; + + /* + * Check for slave role for LS + */ + if (msg->sc_ca->ca_m && + msg->sc_ca->ca_i && + msg->sc_ca->ca_o && + msg->sc_ca->ca_mcp.rec_cnt == 0 && + scsp_cmp_id(&msg->sc_ca->ca_mcp.sid, + &msg->sc_ca->ca_mcp.rid) > 0) { + + /* + * Stop the retransmit timer + */ + HARP_CANCEL(&dcsp->sd_ca_rexmt_t); + + /* + * Set the new state + */ + dcsp->sd_ca_state = SCSP_CAFSM_SLAVE; + (void)scsp_cfsm(dcsp, SCSP_CIFSM_CA_SUMM, + (Scsp_msg *)0, (Scsp_if_msg *)0); + + /* + * Save the master's sequence number + */ + dcsp->sd_ca_seq = msg->sc_ca->ca_seq; + + /* + * Send a CA message + */ + rc = scsp_send_ca(dcsp); + } else + /* + * Check for master role for LS + */ + if (!msg->sc_ca->ca_m && + !msg->sc_ca->ca_i && + scsp_cmp_id(&msg->sc_ca->ca_mcp.sid, + &msg->sc_ca->ca_mcp.rid) < 0) { + /* + * Stop the retransmit timer + */ + HARP_CANCEL(&dcsp->sd_ca_rexmt_t); + + /* + * Set the new state + */ + dcsp->sd_ca_state = SCSP_CAFSM_MASTER; + rc = scsp_cfsm(dcsp, SCSP_CIFSM_CA_SUMM, + (Scsp_msg *)0, (Scsp_if_msg *)0); + + /* + * Process the CA message + */ + scsp_process_ca(dcsp, msg->sc_ca); + + /* + * Increment the sequence number + */ + dcsp->sd_ca_seq++; + + /* + * Send a CA in reply + */ + rc = scsp_send_ca(dcsp); + if (rc == 0) { + HARP_TIMER(&dcsp->sd_ca_rexmt_t, + dcsp->sd_ca_rexmt_int, + scsp_ca_retran_timeout); + } + } else { + /* + * Ignore the message, go to Master/Slave Negotiation + */ + dcsp->sd_ca_state = SCSP_CAFSM_NEG; + } + + return(rc); +} + + +/* + * CA finite state machine action 4 + * CA message received while in Cache Summarize Master state -- process + * CA message + * + * Arguments: + * dcsp pointer to DCS control block + * p pointer to received message + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_ca_act_04(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + int rc = 0; + Scsp_msg *msg = (Scsp_msg *)p; + + /* + * If the other side thinks he's the master, or if the + * initialization bit is set, or if the message is out + * of sequence, go back to Master/Slave Negotiation state + */ + if (msg->sc_ca->ca_m || msg->sc_ca->ca_i || + msg->sc_ca->ca_seq < dcsp->sd_ca_seq - 1 || + msg->sc_ca->ca_seq > dcsp->sd_ca_seq) { + HARP_CANCEL(&dcsp->sd_ca_rexmt_t); + dcsp->sd_ca_state = SCSP_CAFSM_NEG; + scsp_dcs_cleanup(dcsp); + return(scsp_ca_act_01(dcsp, (Scsp_msg *)0)); + } + + /* + * Ignore any duplicate messages + */ + if (msg->sc_ca->ca_seq == dcsp->sd_ca_seq - 1) { + return(0); + } + + /* + * Stop the retransmission timer + */ + HARP_CANCEL(&dcsp->sd_ca_rexmt_t); + + /* + * Process the CA message + */ + scsp_process_ca(dcsp, msg->sc_ca); + + /* + * Increment the CA sequence number + */ + dcsp->sd_ca_seq++; + + /* + * If we have no more CSAS records to send and the slave sent + * a message with the 'O' bit off, we're done with Summarize + * state + */ + if (!dcsp->sd_ca_csas && !msg->sc_ca->ca_o) { + /* + * Free any CA message saved for retransmission + */ + if (dcsp->sd_ca_rexmt_msg) { + scsp_free_msg(dcsp->sd_ca_rexmt_msg); + dcsp->sd_ca_rexmt_msg = (Scsp_msg *)0; + } + + /* + * If the CRL is empty, we go directly to Aligned state; + * otherwise, we go to Update Cache and send a CSUS + */ + if (!dcsp->sd_crl) { + /* + * Go to Aligned state + */ + dcsp->sd_ca_state = SCSP_CAFSM_ALIGNED; + rc = scsp_cfsm(dcsp, SCSP_CIFSM_CA_ALIGN, + (Scsp_msg *)0, + (Scsp_if_msg *)0); + } else { + /* + * Go to Cache Update state + */ + dcsp->sd_ca_state = SCSP_CAFSM_UPDATE; + (void)scsp_cfsm(dcsp, SCSP_CIFSM_CA_UPD, + (Scsp_msg *)0, + (Scsp_if_msg *)0); + rc = scsp_send_csus(dcsp); + } + } else { + /* + * There are more CSAS records to be exchanged-- + * continue the cache exchange + */ + rc = scsp_send_ca(dcsp); + } + + return(rc); +} + + +/* + * CA finite state machine action 5 + * CA message received while in Cache Summarize Slave state -- process + * CA message + * + * Arguments: + * dcsp pointer to DCS control block + * p pointer to received message + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_ca_act_05(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + int rc = 0; + Scsp_msg *msg = (Scsp_msg *)p; + + /* + * If the other side thinks we're the master, or if the + * initialization bit is set, or if the message is out + * of sequence, go back to Master/Slave Negotiation state + */ + if (!msg->sc_ca->ca_m || msg->sc_ca->ca_i || + msg->sc_ca->ca_seq < dcsp->sd_ca_seq || + msg->sc_ca->ca_seq > dcsp->sd_ca_seq + 1) { + HARP_CANCEL(&dcsp->sd_ca_rexmt_t); + dcsp->sd_ca_state = SCSP_CAFSM_NEG; + scsp_dcs_cleanup(dcsp); + return(scsp_ca_act_01(dcsp, (Scsp_msg *)0)); + } + + /* + * If this is a duplicate, retransmit the last message + */ + if (msg->sc_ca->ca_seq == dcsp->sd_ca_seq) { + if (dcsp->sd_ca_rexmt_msg) { + rc = scsp_send_msg(dcsp, dcsp->sd_ca_rexmt_msg); + if (rc == 0) { + HARP_TIMER(&dcsp->sd_ca_rexmt_t, + dcsp->sd_ca_rexmt_int, + scsp_ca_retran_timeout); + } + } + return(rc); + } + + /* + * Free the last CA message + */ + if (dcsp->sd_ca_rexmt_msg) { + scsp_free_msg(dcsp->sd_ca_rexmt_msg); + dcsp->sd_ca_rexmt_msg = (Scsp_msg *)0; + } + + /* + * Process the CA message + */ + scsp_process_ca(dcsp, msg->sc_ca); + + /* + * Increment the CA sequence number + */ + dcsp->sd_ca_seq++; + + /* + * Answer the CA message + */ + rc = scsp_send_ca(dcsp); + if (rc) + return(rc); + + /* + * If we're done sending CSAS records and the other side is, + * too, we're done with Summarize state + */ + if (!dcsp->sd_ca_csas && !msg->sc_ca->ca_o) { + /* + * If the CRL is empty, we go directly to Aligned state; + * otherwise, we go to Update Cache and send a CSUS + */ + if (!dcsp->sd_crl) { + /* + * Go to Aligned state + */ + dcsp->sd_ca_state = SCSP_CAFSM_ALIGNED; + rc = scsp_cfsm(dcsp, SCSP_CIFSM_CA_ALIGN, + (Scsp_msg *)0, + (Scsp_if_msg *)0); + } else { + /* + * Go to Cache Update state + */ + dcsp->sd_ca_state = SCSP_CAFSM_UPDATE; + HARP_CANCEL(&dcsp->sd_ca_rexmt_t); + HARP_TIMER(&dcsp->sd_ca_rexmt_t, + dcsp->sd_ca_rexmt_int, + scsp_ca_retran_timeout); + (void)scsp_cfsm(dcsp, SCSP_CIFSM_CA_UPD, + (Scsp_msg *)0, + (Scsp_if_msg *)0); + rc = scsp_send_csus(dcsp); + } + } + + return(rc); +} + + +/* + * CA finite state machine action 6 + * Retransmit timer expired -- retransmit last CA message + * + * Arguments: + * dcsp pointer to DCS control block + * p ignored + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_ca_act_06(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + int rc; + + /* + * Resend the CA message + */ + rc = scsp_send_msg(dcsp, dcsp->sd_ca_rexmt_msg); + + /* + * Restart the retransmit timer + */ + if (rc == 0) { + HARP_TIMER(&dcsp->sd_ca_rexmt_t, dcsp->sd_ca_rexmt_int, + scsp_ca_retran_timeout); + } + + return(rc); +} + + +/* + * CA finite state machine action 7 + * CSU Solicit received -- send it to the client interface FSM + * + * Arguments: + * dcsp pointer to DCS control block + * p pointer to received message + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_ca_act_07(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + int rc; + Scsp_msg *msg = (Scsp_msg *)p; + + /* + * Cancel the CA retransmit timer and free any CA message + * saved for retransmission + */ + if (dcsp->sd_ca_rexmt_msg) { + HARP_CANCEL(&dcsp->sd_ca_rexmt_t); + scsp_free_msg(dcsp->sd_ca_rexmt_msg); + dcsp->sd_ca_rexmt_msg = (Scsp_msg *)0; + } + + /* + * Pass the CSUS to the client interface FSM + */ + rc = scsp_cfsm(dcsp, SCSP_CIFSM_CSU_SOL, msg, + (Scsp_if_msg *)0); + + return(rc); +} + + +/* + * CA finite state machine action 8 + * CSU Request received -- pass it to the client interface FSM + * + * Arguments: + * dcsp pointer to DCS control block + * p pointer to received message + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_ca_act_08(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + int rc; + Scsp_msg *msg = (Scsp_msg *)p; + Scsp_csu_msg *csusp; + Scsp_csa *csap; + + /* + * Check whether this messages answers a CSUS + */ + scsp_csus_ack(dcsp, msg); + + /* + * If all CSAs requestd in CSUS messages have been + * received, the cache is aligned, so go to Aligned State + */ + if (!dcsp->sd_csus_rexmt_msg && !dcsp->sd_crl && + dcsp->sd_ca_state != SCSP_CAFSM_ALIGNED) { + dcsp->sd_ca_state = SCSP_CAFSM_ALIGNED; + rc = scsp_cfsm(dcsp, SCSP_CIFSM_CA_ALIGN, + (Scsp_msg *)0, (Scsp_if_msg *)0); + } + + /* + * Pass the CSU Req to the client interface FSM + */ + rc = scsp_cfsm(dcsp, SCSP_CIFSM_CSU_REQ, msg, + (Scsp_if_msg *)0); + + /* + * Move the CSA chain from the message to the list of + * requests that need acknowledgements + */ + for (csap = msg->sc_csu_msg->csu_csa_rec; csap; + csap = csap->next) { + LINK2TAIL(csap, Scsp_csa, dcsp->sd_csu_ack_pend, next); + } + msg->sc_csu_msg->csu_csa_rec = (Scsp_csa *)0; + + return(rc); +} + + +/* + * CA finite state machine action 9 + * CA Retransmit timer expired in Update Cache or Aligned state--free + * the saved CA message + * + * Arguments: + * dcsp pointer to DCS control block + * p ignored + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_ca_act_09(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + /* + * Free any CA message saved for retransmission + */ + if (dcsp->sd_ca_rexmt_msg) { + scsp_free_msg(dcsp->sd_ca_rexmt_msg); + dcsp->sd_ca_rexmt_msg = (Scsp_msg *)0; + } + + return(0); +} + + +/* + * CA finite state machine action 10 + * CSU Reply received -- Process the message + * + * Arguments: + * dcsp pointer to DCS control block + * p pointer to received message + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_ca_act_10(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + int rc = 0; + Scsp_msg *msg = (Scsp_msg *)p; + Scsp_csu_rexmt *rxp, *next_rxp; + Scsp_csa *csap, *next_csap, *mcp; + + /* + * Dequeue acknowledged CSAs. For each CSAS in the received + * message, find the corresponding CSA on the CSU Request + * retransmit queue. Remove the CSA from the queue; if this + * results in the retransmit queue entry being empty, delete + * the entry. If the DCS has a newer CSA, send a CSUS to + * request it. + * + * Caution--potentially confusing lack of indentation ahead. + */ + for (mcp = msg->sc_csu_msg->csu_csa_rec; mcp; + mcp = mcp->next) { + for (rxp = dcsp->sd_csu_rexmt; rxp; rxp = next_rxp) { + next_rxp = rxp->sr_next; + for (csap = rxp->sr_csa; csap; csap = next_csap) { + next_csap = csap->next; + if (scsp_cmp_key(&csap->key, &mcp->key) || + scsp_cmp_id(&csap->oid, &mcp->oid)) + continue; + /* + * Found a CSA whose key and ID are equal to + * those in the CSU Reply + */ + if (csap->seq == mcp->seq) { + /* + * The queued seq no is equal to the + * received seq no--the CSA is acknowledged + */ + UNLINK(csap, Scsp_csa, rxp->sr_csa, next); + SCSP_FREE_CSA(csap); + } else if (csap->seq < mcp->seq) { + /* + * Queued seq no is less than received. + * We must dequeue the CSA and send a + * CSUS to request the more-up-to-date + * cache entry. + */ + UNLINK(mcp, Scsp_csa, + msg->sc_csu_msg->csu_csa_rec, + next); + LINK2TAIL(mcp, Scsp_csa, dcsp->sd_crl, next); + UNLINK(csap, Scsp_csa, rxp->sr_csa, next); + SCSP_FREE_CSA(csap); + if (!dcsp->sd_csus_rexmt_msg) { + rc = scsp_send_csus(dcsp); + if (rc) { + return(rc); + } + } + } + /* + * Queued seq no is greater than + * received. Ignore the received CSAS. + */ + + /* + * If the retransmission block is empty, stop the + * timer and free it + */ + if (!rxp->sr_csa) { + HARP_CANCEL(&rxp->sr_t); + UNLINK(rxp, Scsp_csu_rexmt, + dcsp->sd_csu_rexmt, sr_next); + UM_FREE(rxp); + } + + break; + } /* for (csap = ... */ + } /* for (rxp = ... */ + } /* for (mcp = ... */ + + return(rc); +} + + +/* + * CA finite state machine action 11 + * Updated cache entry -- update the summary cache and send a + * CSU Request + * + * Arguments: + * dcsp pointer to DCS control block + * p pointer to CSA describing new cache entry + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_ca_act_11(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + int rc, state; + Scsp_csa *csap = (Scsp_csa *)p; + Scsp_cse *csep; + + /* + * Get the state of the CSA + */ + switch(dcsp->sd_server->ss_pid) { + case SCSP_PROTO_ATMARP: + state = csap->atmarp_data->sa_state; + break; + default: + SCSP_FREE_CSA(csap); + return(EINVAL); + } + + if (state < SCSP_ASTATE_NEW || state > SCSP_ASTATE_DEL) { + SCSP_FREE_CSA(csap); + return(EINVAL); + } + + /* + * Look up the cache summary entry for the CSA + */ + SCSP_LOOKUP(dcsp->sd_server, &csap->key, csep); + + /* + * Process ATMARP entries + */ + if (dcsp->sd_server->ss_pid == SCSP_PROTO_ATMARP) { + switch(state) { + case SCSP_ASTATE_NEW: + case SCSP_ASTATE_UPD: + /* + * Add the entry if we don't have it already + */ + if (!csep) { + csep = (Scsp_cse *)UM_ALLOC( + sizeof(Scsp_cse)); + if (!csep) + scsp_mem_err("scsp_ca_act_11: sizeof(Scsp_cse)"); + UM_ZERO(csep, sizeof(Scsp_cse)); + + csep->sc_key = csap->key; + SCSP_ADD(dcsp->sd_server, csep); + } + + /* + * Update the cache summary entry + */ + csep->sc_seq = csap->seq; + csep->sc_oid = csap->oid; + break; + case SCSP_ASTATE_DEL: + /* + * Delete any entry, but don't send the + * delete to the DCS + */ + if (csep) { + SCSP_DELETE(dcsp->sd_server, csep); + UM_FREE(csep); + } + + SCSP_FREE_CSA(csap); + return(0); + } + } + + /* + * Send the CSA in a CSU Request + */ + csap->trans_ct = 0; + rc = scsp_send_csu_req(dcsp, csap); + + return(rc); +} + + +/* + * CA finite state machine action 12 + * CSUS retransmit timer expired--send a CSUS with any pending CSA + * records + * + * Arguments: + * dcsp pointer to DCS control block + * p ignored + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_ca_act_12(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + int rc; + + rc = scsp_send_csus(dcsp); + + return(rc); +} + + +/* + * CA finite state machine action 13 + * CSU retransmit timer fired in Update or Aligned state-- + * retransmit CSU Req + * + * Arguments: + * dcsp pointer to DCS control block + * p pointer to retransmission block whose timer fired + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_ca_act_13(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + int rc = 0; + Scsp_csu_rexmt *rxp = (Scsp_csu_rexmt *)p; + Scsp_csa *csap, *csap1, *next_csap; + + /* + * Unlink and free the retransmit request block + */ + csap = rxp->sr_csa; + UNLINK(rxp, Scsp_csu_rexmt, dcsp->sd_csu_rexmt, sr_next); + UM_FREE(rxp); + + /* + * Increment the transmission count for the CSAs in the request + */ + for (csap1 = csap; csap1; csap1 = next_csap) { + next_csap = csap1->next; + csap1->trans_ct++; + if (csap1->trans_ct >= dcsp->sd_csu_rexmt_max) { + /* + * We've already sent this as many times as + * the limit allows. Drop this CSA. + */ + UNLINK(csap1, Scsp_csa, csap, next); + SCSP_FREE_CSA(csap1); + } + } + + /* + * Send another CSU Request with the CSA list, if it isn't + * empty now + */ + if (csap) { + rc = scsp_send_csu_req(dcsp, csap); + } + + return(rc); +} + + +/* + * CA finite state machine action 14 + * Updated cache entry in Master/Slave Negotiation, Master, or + * Slave state--add entry to cache and CSA list + * + * Arguments: + * dcsp pointer to DCS control block + * p pointer to new cache summary entry + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_ca_act_14(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + Scsp_csa *csap = (Scsp_csa *)p; + Scsp_cse *csep, *csep1; + + /* + * Check to see whether we already have this + */ + SCSP_LOOKUP(dcsp->sd_server, &csap->key, csep); + + /* + * If we don't already have it and it's not being deleted, + * build a new cache summary entry + */ + if (!csep && !csap->null) { + /* + * Get memory for a new entry + */ + csep = (Scsp_cse *)UM_ALLOC(sizeof(Scsp_cse)); + if (!csep) { + scsp_mem_err("scsp_ca_act_14: sizeof(Scsp_cse)"); + } + UM_ZERO(csep, sizeof(Scsp_cse)); + + /* + * Fill out the new cache entry + */ + csep->sc_seq = csap->seq; + csep->sc_key = csap->key; + csep->sc_oid = csap->oid; + + /* + * Duplicate the new cache entry + */ + csep1 = scsp_dup_cse(csep); + + /* + * Add entry to the summary cache and the CSAS list + */ + SCSP_ADD(dcsp->sd_server, csep); + LINK2TAIL(csep1, Scsp_cse, dcsp->sd_ca_csas, sc_next); + } else { + /* + * We already have the entry. Find it on the CSAS + * list. + */ + for (csep1 = dcsp->sd_ca_csas; csep1; + csep1 = csep1->sc_next) { + if (scsp_cmp_key(&csep->sc_key, + &csep1->sc_key) == 0) + break; + } + + /* + * Update or delete the entry + */ + if (csap->null) { + /* + * The null flag is set--delete the entry + */ + SCSP_DELETE(dcsp->sd_server, csep); + UM_FREE(csep); + if (csep1) { + UNLINK(csep1, Scsp_cse, + dcsp->sd_ca_csas, + sc_next); + UM_FREE(csep1); + } + } else { + /* + * Update the entry + */ + csep->sc_seq = csap->seq; + csep->sc_oid = csap->oid; + if (!csep1) { + csep1 = scsp_dup_cse(csep); + LINK2TAIL(csep1, Scsp_cse, + dcsp->sd_ca_csas, sc_next); + } else { + csep1->sc_seq = csap->seq; + csep1->sc_oid = csap->oid; + } + } + } + + return(0); +} + + +/* + * CA finite state machine action 15 + * CA message received in Update Cache state--if we have a saved CA + * message, retransmit it; otherwise, go to Master/Slave Negotiation + * state + * + * Arguments: + * dcsp pointer to DCS control block + * p ignored + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_ca_act_15(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + int rc; + Scsp_msg *msg = (Scsp_msg *)p; + + /* + * If we don't have a saved CA message, or the sequence no. in + * the received message isn't right, fall back to Master/Slave + * Negotiation state + */ + if (!dcsp->sd_ca_rexmt_msg || + msg->sc_ca->ca_seq != dcsp->sd_ca_seq) { + dcsp->sd_ca_state = SCSP_CAFSM_NEG; + scsp_dcs_cleanup(dcsp); + rc = scsp_ca_act_01(dcsp, (Scsp_msg *)0); + } else { + /* + * Retransmit the saved CA message and reset the + * CA timer + */ + rc = scsp_send_msg(dcsp, dcsp->sd_ca_rexmt_msg); + if (rc == 0) { + HARP_CANCEL(&dcsp->sd_ca_rexmt_t); + HARP_TIMER(&dcsp->sd_ca_rexmt_t, + dcsp->sd_ca_rexmt_int, + scsp_ca_retran_timeout); + } + } + + return(rc); +} + + +/* + * CA finite state machine action 16 + * Update Response received from client in Update Cache or Aligned + * state. Move the acknowledged CSA to the acknowledged queue. If + * the list of CSAs pending acknowledgement is empty, send a CSU + * Reply. + * + * Arguments: + * dcsp pointer to DCS control block + * p pointer to message from client + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_ca_act_16(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + int found, rc = 0; + Scsp_if_msg *cmsg = (Scsp_if_msg *)p; + Scsp_csa *csap; + + /* + * Find the acknowledged CSA + */ + for (csap = dcsp->sd_csu_ack_pend, found = 0; csap && !found; + csap = csap->next) { + switch (dcsp->sd_server->ss_pid) { + case SCSP_PROTO_ATMARP: + found = ((scsp_cmp_key(&csap->key, + &cmsg->si_atmarp.sa_key) == 0) && + (scsp_cmp_id(&csap->oid, + &cmsg->si_atmarp.sa_oid) == 0)); + break; + default: + /* + * Protocol not implemented + */ + return(EPROTONOSUPPORT); + } + if (found) + break; + } + + if (!found) { + if (scsp_trace_mode & SCSP_TRACE_CAFSM) { + scsp_trace("scsp_ca_act_16: can't find CSA entry for Update Response\n"); + } + return(0); + } + + if (cmsg->si_rc == SCSP_RSP_OK) { + /* + * The server accepted the cache entry + */ + + /* + * Update SCSP's cache + */ + scsp_update_cache(dcsp, csap); + + /* + * Send this CSA to any other DCSs in the server group + */ + rc = scsp_propagate_csa(dcsp, csap); + } + + /* + * Move the CSA from the ACK pending queue to the + * acknowledged queue + */ + UNLINK(csap, Scsp_csa, dcsp->sd_csu_ack_pend, next); + LINK2TAIL(csap, Scsp_csa, dcsp->sd_csu_ack, next); + if (!dcsp->sd_csu_ack_pend) { + /* + * ACK pending list is empty--send a CSU Reply + */ + csap = dcsp->sd_csu_ack; + dcsp->sd_csu_ack = (Scsp_csa *)0; + rc = scsp_send_csu_reply(dcsp, csap); + } + + return(rc); +} + + +/* + * CA finite state machine action 17 + * Ignore an event. + * + * Arguments: + * dcsp pointer to DCS control block + * p ignored + * + * Returns: + * always returns 0 + * + */ +int +scsp_ca_act_17(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + return(0); +} + + +/* + * CA finite state machine action 18 + * Updated cache entry in Down state--add entry to summary cache + * + * Arguments: + * dcsp pointer to DCS control block + * p pointer to new cache summary entry + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_ca_act_18(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + Scsp_csa *csap = (Scsp_csa *)p; + + /* + * Update the cache as appropriate + */ + scsp_update_cache(dcsp, csap); + + return(0); +} + + +/* + * CA finite state machine action 19 + * Update Response received from client in Master/Slave Negotiation + * state. Update the cache as appropriate. + * + * Arguments: + * dcsp pointer to DCS control block + * p pointer to message from client + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_ca_act_19(dcsp, p) + Scsp_dcs *dcsp; + void *p; +{ + int found, rc = 0; + Scsp_if_msg *cmsg = (Scsp_if_msg *)p; + Scsp_csa *csap; + + /* + * Ignore the message if the client rejected the update + */ + if (cmsg->si_rc != SCSP_RSP_OK) { + return(0); + } + + /* + * Create a CSAS from the client's update + */ + csap = (Scsp_csa *)UM_ALLOC(sizeof(Scsp_csa)); + if (!csap) { + scsp_mem_err("scsp_ca_act_19: sizeof(Scsp_csa)"); + } + UM_ZERO(csap, sizeof(Scsp_csa)); + + csap->hops = 1; + switch (dcsp->sd_server->ss_pid) { + case SCSP_PROTO_ATMARP: + csap->null = cmsg->si_atmarp.sa_state == + SCSP_ASTATE_DEL; + csap->seq = cmsg->si_atmarp.sa_seq; + csap->key = cmsg->si_atmarp.sa_key; + csap->oid = cmsg->si_atmarp.sa_oid; + break; + default: + return(EINVAL); + } + + /* + * Update SCSP's cache + */ + scsp_update_cache(dcsp, csap); + + return(0); +} diff --git a/usr.sbin/atm/scspd/scsp_config.c b/usr.sbin/atm/scspd/scsp_config.c new file mode 100644 index 0000000..99eca7a --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_config.c @@ -0,0 +1,1160 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: scsp_config.c,v 1.3 1998/08/13 20:11:14 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * Configuration file processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_config.c,v 1.3 1998/08/13 20:11:14 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" + + +/* + * Global variables + */ +FILE *cfg_file; +Scsp_server *current_server; +Scsp_dcs *current_dcs; + + + +/* + * Process the configuration file + * + * This routine is called when the daemon starts, and it can also be + * called while it is running, as the result of a SIGHUP signal. It + * therefore has to be capable of both configuring the daemon from + * scratch and modifying the configuration of a running daemon. + * + * Arguments: + * cfn configuration file name + * + * Returns: + * 0 configuration read with no errors + * else error found in configuration file + * + */ +int +scsp_config(cfn) + char *cfn; +{ + int rc; + Scsp_server *ssp, *snext; + + /* + * Open the configuration file + */ + cfg_file = fopen(cfn, "r"); + if (!cfg_file) { + scsp_log(LOG_ERR, "can't open config file %s", + (void *)cfn); + exit(1); + } + + /* + * Initialize current interface pointer + */ + current_server = (Scsp_server *)0; + + /* + * Clear marks on any existing servers + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + ssp->ss_mark = 0; + } + + /* + * Scan the configuration file, processing each line as + * it is read + */ + rc = yyparse(); + + /* + * Close the configuration file + */ + fclose(cfg_file); + + /* + * Delete any server entries that weren't updated + */ + for (ssp = scsp_server_head; ssp; ssp = snext) { + snext = ssp->ss_next; + if (!ssp->ss_mark) + scsp_server_delete(ssp); + } + + return(rc); +} + + +/* + * Prepare for SCSP DCS setup + * + * This routine is called from yyparse() when a DCS command is found. + * + * Arguments: + * none + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +start_dcs() +{ + Scsp_dcs *dcsp; + + /* + * Make sure we have a current server block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + /* + * Allocate a DCS block + */ + dcsp = (Scsp_dcs *)UM_ALLOC(sizeof(Scsp_dcs)); + if (!dcsp) { + scsp_mem_err("start_dcs: sizeof(Scsp_dcs)"); + } + UM_ZERO(dcsp, sizeof(Scsp_dcs)); + + /* + * Fill out DCS links and default values + */ + dcsp->sd_server = current_server; + dcsp->sd_addr.address_format = T_ATM_ABSENT; + dcsp->sd_subaddr.address_format = T_ATM_ABSENT; + dcsp->sd_sock = -1; + dcsp->sd_ca_rexmt_int = SCSP_CAReXmitInterval; + dcsp->sd_csus_rexmt_int = SCSP_CSUSReXmitInterval; + dcsp->sd_hops = SCSP_CSA_HOP_CNT; + dcsp->sd_csu_rexmt_int = SCSP_CSUReXmitInterval; + dcsp->sd_csu_rexmt_max = SCSP_CSUReXmitMax; + LINK2TAIL(dcsp, Scsp_dcs, current_server->ss_dcs, sd_next); + + current_dcs = dcsp; + return(0); +} + + +/* + * Finish up server configuration + * + * This routine is called from yyparse() to at the end of a DCS + * command. It checks that required fields are set and finishes + * up the DCS block. + * + * Arguments: + * none + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +finish_dcs() +{ + int rc = 0; + Scsp_dcs *dcsp; + Scsp_server *ssp; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + ssp = current_server; + dcsp = current_dcs; + + /* + * Make sure the DCS ID is set + */ + if (dcsp->sd_dcsid.id_len == 0) { + parse_error("DCS ID not set"); + rc++; + } + + /* + * Make sure the ATM address is set + */ + if (dcsp->sd_addr.address_format == T_ATM_ABSENT) { + parse_error("DCS ATM address not set"); + rc++; + } + + current_dcs = (Scsp_dcs *)0; + return(rc); +} + + +/* + * Configure DCS ATM address + * + * This routine is called from yyparse() to process an ATMaddr command. + * + * Arguments: + * ap pointer to DCS's ATM address (in ASCII) + * sap pointer to DCS's ATM subaddress (in ASCII) + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_dcs_addr(ap, sap) + char *ap, *sap; +{ + Scsp_dcs *dcsp; + Atm_addr addr, subaddr; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + dcsp = current_dcs; + + /* + * Initialize + */ + UM_ZERO(&addr, sizeof(addr)); + addr.address_format = T_ATM_ABSENT; + UM_ZERO(&subaddr, sizeof(subaddr)); + subaddr.address_format = T_ATM_ABSENT; + + /* + * Convert the ATM address from character to internal format + */ + if (ap) { + addr.address_length = get_hex_atm_addr(ap, + (u_char *)addr.address, strlen(ap)); + if (addr.address_length == 0) { + parse_error("invalid ATM address"); + return(1); + } + if (addr.address_length == sizeof(Atm_addr_nsap)) { + addr.address_format = T_ATM_ENDSYS_ADDR; + } else if (addr.address_length <= + sizeof(Atm_addr_e164)) { + addr.address_format = T_ATM_E164_ADDR; + } else { + parse_error("invalid ATM address"); + return(1); + } + } + + /* + * Convert the ATM subaddress from character to internal format + */ + if (sap) { + subaddr.address_length = get_hex_atm_addr(sap, + (u_char *)subaddr.address, strlen(sap)); + if (subaddr.address_length == 0) { + parse_error("invalid ATM address"); + return(1); + } + if (subaddr.address_length == sizeof(Atm_addr_nsap)) { + subaddr.address_format = T_ATM_ENDSYS_ADDR; + } else if (subaddr.address_length <= + sizeof(Atm_addr_e164)) { + subaddr.address_format = T_ATM_E164_ADDR; + } else { + parse_error("invalid ATM subaddress"); + return(1); + } + } + + /* + * Make sure we have a legal ATM address type combination + */ + if (((addr.address_format != T_ATM_ENDSYS_ADDR) || + (subaddr.address_format != T_ATM_ABSENT)) && + ((addr.address_format != T_ATM_E164_ADDR) || + (subaddr.address_format != T_ATM_ENDSYS_ADDR))) { + parse_error("invalid address/subaddress combination"); + return(1); + } + + /* + * Save the address and subaddress + */ + ATM_ADDR_COPY(&addr, &dcsp->sd_addr); + ATM_ADDR_COPY(&subaddr, &dcsp->sd_subaddr); + + return(0); +} + + +/* + * Configure CA retransmit interval for DCS + * + * This routine is called from yyparse() to process a CAReXmitInt + * command. + * + * Arguments: + * val time interval + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_dcs_ca_rexmit(val) + int val; +{ + Scsp_dcs *dcsp; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + dcsp = current_dcs; + + + /* + * Validate the interval + */ + if (val <= 0 || val > 1024) { + parse_error("invalid CA retransmit interval"); + return(1); + } + + /* + * Set CA retransmit interval + */ + dcsp->sd_ca_rexmt_int = val; + + return(0); +} + + +/* + * Configure CSUS retransmit interval for DCS + * + * This routine is called from yyparse() to process a CSUSReXmitInt + * command. + * + * Arguments: + * val time interval + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_dcs_csus_rexmit(val) + int val; +{ + Scsp_dcs *dcsp; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + dcsp = current_dcs; + + + /* + * Validate the interval + */ + if (val <= 0 || val > 1024) { + parse_error("invalid CSUS retransmit interval"); + return(1); + } + + /* + * Set CSUS retransmit interval + */ + dcsp->sd_csus_rexmt_int = val; + + return(0); +} + + +/* + * Configure CSU retransmit interval for DCS + * + * This routine is called from yyparse() to process a CSUReXmitInt + * command. + * + * Arguments: + * val time interval + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_dcs_csu_rexmit(val) + int val; +{ + Scsp_dcs *dcsp; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + dcsp = current_dcs; + + + /* + * Validate the interval + */ + if (val <= 0 || val > 1024) { + parse_error("invalid CSU retransmit interval"); + return(1); + } + + /* + * Set CSU retransmit interval + */ + dcsp->sd_csu_rexmt_int = val; + + return(0); +} + + +/* + * Configure CSU retransmit limit for DCS + * + * This routine is called from yyparse() to process a CSUReXmitMax + * command. + * + * Arguments: + * val time interval + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_dcs_csu_rexmit_max(val) + int val; +{ + Scsp_dcs *dcsp; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + dcsp = current_dcs; + + + /* + * Validate the interval + */ + if (val <= 0 || val > 1024) { + parse_error("invalid CSU retransmit maximum"); + return(1); + } + + /* + * Set CSU retransmit limit + */ + dcsp->sd_csu_rexmt_max = val; + + return(0); +} + + +/* + * Configure Hello dead factor for DCS + * + * This routine is called from yyparse() to process a HelloDead + * command. + * + * Arguments: + * val number of times Hello interval has to expire before + * a DCS is considered dead + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_dcs_hello_df(val) + int val; +{ + Scsp_dcs *dcsp; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + dcsp = current_dcs; + + + /* + * Validate the limit + */ + if (val <= 0 || val > 1024) { + parse_error("invalid Hello dead factor"); + return(1); + } + + /* + * Set Hello dead factor + */ + dcsp->sd_hello_df = val; + + return(0); +} + + +/* + * Configure Hello interval for DCS + * + * This routine is called from yyparse() to process a HelloInt + * command. + * + * Arguments: + * val time interval + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_dcs_hello_int(val) + int val; +{ + Scsp_dcs *dcsp; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + dcsp = current_dcs; + + + /* + * Validate the interval + */ + if (val <= 0 || val > 1024) { + parse_error("invalid Hello interval"); + return(1); + } + + /* + * Set Hello interval + */ + dcsp->sd_hello_int = val; + + return(0); +} + + +/* + * Configure hop count for SCSP server + * + * This routine is called from yyparse() to process a Hops command. + * + * Arguments: + * hops number of hops + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_dcs_hops(hops) + int hops; +{ + Scsp_dcs *dcsp; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + dcsp = current_dcs; + + + /* + * Validate the count + */ + if (hops <= 0 || hops > 1024) { + parse_error("invalid hop count"); + return(1); + } + + /* + * Set hop count + */ + dcsp->sd_hops = hops; + + return(0); +} + + +/* + * Configure DCS ID + * + * This routine is called from yyparse() to process an ID command. + * + * Arguments: + * name pointer to DCS's DNS name or IP address (in ASCII) + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_dcs_id(name) + char *name; +{ + Scsp_dcs *dcsp; + Scsp_server *ssp; + struct sockaddr_in *ip_addr; + + /* + * Make sure we have a current server block and DCS block + */ + if (!current_server) { + parse_error("server not found"); + return(1); + } + + if (!current_dcs) { + parse_error("server not found"); + return(1); + } + ssp = current_server; + dcsp = current_dcs; + + /* + * Convert the DNS name or IP address + */ + ip_addr = get_ip_addr(name); + if (!ip_addr) { + parse_error("invalid DCS IP address"); + return(1); + } + + /* + * Verify the address length + */ + if (ssp->ss_id_len != sizeof(ip_addr->sin_addr)) { + parse_error("invalid DCS ID length"); + return(1); + } + + /* + * Set the ID in the DCS block + */ + dcsp->sd_dcsid.id_len = ssp->ss_id_len; + UM_COPY(&ip_addr->sin_addr, dcsp->sd_dcsid.id, ssp->ss_id_len); + + return(0); +} + + +/* + * Configure network interface for SCSP server + * + * This routine is called from yyparse() to process a Netif command. + * It verifies the network interface name, gets interface information + * from the kernel, and sets the appropriate fields in the server + * control block. + * + * Arguments: + * netif pointer to network interface name + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_intf(netif) + char *netif; +{ + int rc; + Scsp_server *ssp; + + /* + * Get the current network interface address + */ + ssp = current_server; + if (!ssp) { + parse_error("Server not found"); + rc = 1; + goto set_intf_done; + } + + /* + * Make sure we're configuring a valid + * network interface + */ + rc = verify_nif_name(netif); + if (rc == 0) { + parse_error("%s is not a valid network interface", + (void *)netif); + rc = 1; + goto set_intf_done; + } else if (rc < 0) { + scsp_log(LOG_ERR, "Netif name verify error"); + exit(1); + } + + /* + * Save the server's network interface name + */ + strcpy(ssp->ss_intf, netif); + rc = 0; + +set_intf_done: + return(rc); +} + + +/* + * Configure protocol for SCSP server + * + * This routine is called from yyparse() to process a Protocol command. + * + * Arguments: + * proto SCSP protocol being configured + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_protocol(proto) + int proto; +{ + Scsp_server *ssp; + + /* + * Get address of current server block + */ + ssp = current_server; + if (!ssp) { + parse_error("server not found"); + return(1); + } + + /* + * Process based on protocol ID + */ + switch(proto) { + case SCSP_PROTO_ATMARP: + ssp->ss_pid = proto; + ssp->ss_id_len = SCSP_ATMARP_ID_LEN; + ssp->ss_ckey_len = SCSP_ATMARP_KEY_LEN; + break; + case SCSP_PROTO_NHRP: + ssp->ss_pid = proto; + ssp->ss_id_len = SCSP_NHRP_ID_LEN; + ssp->ss_ckey_len = SCSP_NHRP_KEY_LEN; + break; + case SCSP_PROTO_MARS: + case SCSP_PROTO_DHCP: + case SCSP_PROTO_LNNI: + default: + parse_error("invalid protocol"); + return(1); + } + + return(0); +} + + +/* + * Configure server group for SCSP server + * + * This routine is called from yyparse() to process a ServerGroupID + * command. + * + * Arguments: + * sgid server group id + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_server_group(sgid) + int sgid; +{ + Scsp_server *ssp; + + /* + * Get address of current server block + */ + ssp = current_server; + if (!ssp) { + parse_error("server not found"); + return(1); + } + + /* + * Validate server group ID + */ + if (sgid <= 0) { + parse_error("invalid server group ID"); + return(1); + } + + /* + * Save the ID + */ + ssp->ss_sgid = sgid; + + return(0); +} + + +/* + * Prepare for SCSP server setup + * + * This routine is called from yyparse() when a Server statment is + * found. + * + * Arguments: + * name pointer to LIS name + * + * Returns: + * 0 success + * else error encountered + * + */ +int +start_server(name) + char *name; +{ + int i; + Scsp_server *ssp; + Scsp_dcs *dcsp, *next_dcs; + Scsp_cse *csep, *next_cse; + + /* + * See if we already have an entry for this name + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + if (strcasecmp(ssp->ss_name, name) == 0) + break; + } + + if (ssp) { + /* + * Log the fact that we're updating the entry + */ + scsp_log(LOG_INFO, "updating server entry for %s", + (void *)name); + + /* + * Free the existing cache + */ + for (i = 0; i < SCSP_HASHSZ; i++) { + for (csep = ssp->ss_cache[i]; csep; + csep = next_cse) { + next_cse = csep->sc_next; + UNLINK(csep, Scsp_cse, ssp->ss_cache[i], + sc_next); + UM_FREE(csep); + } + } + + /* + * Delete existing DCS blocks + */ + for (dcsp = ssp->ss_dcs; dcsp; dcsp = next_dcs) { + next_dcs = dcsp->sd_next; + scsp_dcs_delete(dcsp); + } + } else { + /* + * Get a new server entry + */ + ssp = (Scsp_server *)UM_ALLOC(sizeof(Scsp_server)); + if (!ssp) { + scsp_log(LOG_ERR, "unable to allocate server entry"); + exit(1); + } + UM_ZERO(ssp, sizeof(Scsp_server)); + ssp->ss_sock = -1; + ssp->ss_dcs_lsock = -1; + + /* + * Set the name + */ + ssp->ss_name = strdup(name); + + /* + * Link in the new interface entry + */ + LINK2TAIL(ssp, Scsp_server, scsp_server_head, + ss_next); + } + + /* + * If the mark is already set, this is a duplicate command + */ + if (ssp->ss_mark) { + parse_error("duplicate server \"%s\"", name); + return(1); + } + + /* + * Make this the current interface + */ + current_server = ssp; + + return(0); +} + + +/* + * Finish up server configuration + * + * This routine is called from yyparse() when the end of a server + * statement is reached. It checks that required fields are set + * and marks the entry as processed. + * + * Arguments: + * None + * + * Returns: + * 0 OK + * 1 Error + * + */ +int +finish_server() +{ + int rc = 0; + Scsp_server *ssp; + + /* + * Get the current network interface address + */ + ssp = current_server; + if (!ssp) { + parse_error("Server not found"); + rc++; + } + + /* + * Mark the interface as processed + */ + ssp->ss_mark = 1; + + /* + * Make sure the interface has been configured + */ + if (ssp->ss_intf == (char *)0) { + parse_error("netif missing from server specification"); + rc++; + } + + /* + * Make sure the protocol is set + */ + if (ssp->ss_pid == 0) { + parse_error("protocol missing from server specification"); + rc++; + } + + /* + * Make sure the server group is set + */ + if (ssp->ss_sgid == 0) { + parse_error("server group ID missing from server specification"); + rc++; + } + + /* + * Make sure at least one DCS is configured + */ + if (ssp->ss_dcs == (Scsp_dcs *)0) { + parse_error("no DCS configured for server"); + rc++; + } + + /* + * Mark the end of the server + */ + current_server = (Scsp_server *)0; + + return(rc); +} + + +/* + * Configure log file for SCSP server + * + * This routine is called from yyparse() to process a log File command. + * + * Arguments: + * file name of logging file + * + * Returns: + * 0 success + * 1 error encountered + * + */ +int +set_log_file(file) + char *file; +{ + /* + * Make sure we haven't already got a log file + */ + if (scsp_log_file) { + parse_error("multiple log files specified"); + return(1); + } + + /* + * Open the file + */ + scsp_log_file = fopen(file, "a"); + if (!scsp_log_file) { + parse_error("can't open log file"); + return(1); + } + + return(0); +} diff --git a/usr.sbin/atm/scspd/scsp_config_lex.c b/usr.sbin/atm/scspd/scsp_config_lex.c new file mode 100644 index 0000000..7b77ae6 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_config_lex.c @@ -0,0 +1,528 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: scsp_config_lex.c,v 1.3 1998/08/13 20:11:14 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * Parse a configuration file into tokens + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_config_lex.c,v 1.3 1998/08/13 20:11:14 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" +#include "scsp_config_parse.h" + +/* + * Global variables + */ +int parse_line = 1; + +/* + * Local definitions + */ +#define TOK_MAX_LEN 128 + +/* + * Character classes + */ +#define CHAR_INVALID 0 /* Not allowed */ +#define CHAR_ALPHA 1 /* G-W, Y, Z */ +#define CHAR_HEX_DIGIT 2 /* A-F */ +#define CHAR_X 3 /* X */ +#define CHAR_0 4 /* '0' */ +#define CHAR_DIGIT 5 /* 1-9 */ +#define CHAR_SPACE 6 /* space, tab */ +#define CHAR_DECIMAL 7 /* period */ +#define CHAR_SLASH 8 /* slash */ +#define CHAR_ASTERISK 9 /* asterisk */ +#define CHAR_HASH 10 /* pound sign */ +#define CHAR_SPECIAL 11 /* semicolon, braces */ +#define CHAR_MISC 12 /* chars allowd in file names */ +#define CHAR_EOL 13 /* new line */ +#define CHAR_EOF 14 /* EOF */ +#define CHAR_CNT CHAR_EOF + 1 + +/* + * Character class table (initialized by init_class_tbl()) + */ +static char class_tbl[128]; + +/* + * State table element structure + */ +struct state_entry { + int action; + int next; +}; + +/* + * Scanner states + */ +#define TS_INIT 0 +#define TS_ALPHA 1 +#define TS_INT_1 2 +#define TS_INT 3 +#define TS_HEX 4 +#define TS_SLASH_1 5 +#define TS_COMMENT 6 +#define TS_COMMENT_1 7 +#define TS_FLUSH 8 +#define TS_HEX_1 9 +#define TS_CNT TS_HEX_1 + 1 + +/* + * Token scanner state table + */ +static struct state_entry token_state_tbl[CHAR_CNT][TS_CNT] = { +/* 0 1 2 3 4 5 6 7 8 9 */ +/* bad */{{2,0},{2,0},{2,0},{2,0},{2,0},{2,0},{0,6},{0,6},{0,8},{2,0}}, +/* g-z */{{1,1},{1,1},{1,1},{1,1},{2,0},{1,1},{0,6},{0,6},{0,8},{2,0}}, +/* a-f */{{1,1},{1,1},{1,1},{1,1},{1,9},{1,1},{0,6},{0,6},{0,8},{1,4}}, +/* x */{{1,1},{1,1},{1,4},{1,4},{2,0},{1,1},{0,6},{0,6},{0,8},{2,0}}, +/* 0 */{{1,2},{1,1},{1,3},{1,3},{1,9},{1,1},{0,6},{0,6},{0,8},{1,4}}, +/* 1-9 */{{1,3},{1,1},{1,3},{1,3},{1,9},{1,1},{0,6},{0,6},{0,8},{1,4}}, +/* sp */{{0,0},{6,0},{8,0},{8,0},{7,0},{6,0},{0,6},{0,6},{0,8},{2,0}}, +/* . */{{2,0},{1,1},{1,1},{1,1},{1,4},{1,1},{0,6},{0,6},{0,8},{2,0}}, +/* / */{{1,5},{1,1},{1,1},{1,1},{7,0},{4,8},{0,6},{0,0},{0,8},{2,0}}, +/* * */{{2,0},{6,0},{8,0},{8,0},{7,0},{4,6},{0,7},{0,7},{0,8},{2,0}}, +/* # */{{0,8},{6,0},{8,0},{8,0},{7,0},{6,0},{0,6},{0,6},{0,8},{2,0}}, +/* ;{} */{{3,0},{6,0},{8,0},{8,0},{7,0},{6,0},{0,6},{0,6},{0,8},{2,0}}, +/* Msc */{{2,0},{1,1},{1,1},{1,1},{2,0},{1,1},{0,6},{0,6},{0,8},{2,0}}, +/* EOL */{{0,0},{6,0},{8,0},{8,0},{7,0},{6,0},{0,6},{0,6},{0,0},{2,0}}, +/* EOF */{{9,0},{6,0},{8,0},{8,0},{7,0},{6,0},{2,0},{2,0},{9,0},{2,0}}, +}; + + +/* + * Reserved words + */ +static struct { + char *word; + int token; +} rsvd_word_tbl[] = { + { "ATMaddr", TOK_DCS_ADDR }, + { "ATMARP", TOK_ATMARP }, + { "CAReXmitInt", TOK_DCS_CA_REXMIT_INT }, + { "CSUSReXmitInt", TOK_DCS_CSUS_REXMIT_INT }, + { "CSUReXmitInt", TOK_DCS_CSU_REXMIT_INT }, + { "CSUReXmitMax", TOK_DCS_CSU_REXMIT_MAX }, + { "DCS", TOK_DCS }, + { "DHCP", TOK_DHCP }, + { "familyID", TOK_FAMILY }, + { "file", TOK_LFN }, + { "hops", TOK_DCS_HOP_CNT }, + { "HelloDead", TOK_DCS_HELLO_DF }, + { "HelloInt", TOK_DCS_HELLO_INT }, + { "ID", TOK_DCS_ID }, + { "LNNI", TOK_LNNI }, + { "log", TOK_LOG }, + { "MARS", TOK_MARS }, + { "netif", TOK_NETIF }, + { "NHRP", TOK_NHRP }, + { "protocol", TOK_PROTOCOL }, + { "server", TOK_SERVER }, + { "ServerGroupID", TOK_SRVGRP }, + { "syslog", TOK_SYSLOG }, + { (char *)0, 0 }, +}; + + +/* + * Copy a character string + * + * Make a copy of a character string, using strdup. If strdup fails, + * meaning we're out of memory, then print an error message and exit. + * + * Arguments: + * s string to be copied + * + * Returns: + * char * pointer to area provided by strdup + * + */ +static char * +copy_buffer(s) + char *s; +{ + char *t; + + t = strdup(s); + + if (!t) { + fprintf(stderr, "%s: strdup failed\n", prog); + exit(1); + } + + return(t); +} + + +/* + * Push a character back onto the input stream. + * + * Arguments: + * c character to be pushed + * + * Returns: + * none + * + */ +static void +push_char(c) + char c; +{ + if (c == '\n') + parse_line--; + + ungetc(c, cfg_file); +} + + +/* + * Initialize the character class table. + * + * Set each entry in the character class table to the class + * corresponding to the character. + * + * Arguments: + * tbl pointer to table to be initialized + * + * Returns: + * None + */ +static void +init_class_tbl(tbl) + char *tbl; +{ + int i; + char c; + + /* + * Set up the table for all ASCII characters + */ + for (i=0; isascii((char)i); i++) { + /* + * Clear entry + */ + tbl[i] = CHAR_INVALID; + + /* + * Set entries depending on character type + */ + c = (char)i; + if (c == 'a' || c == 'b' || c == 'c' || + c == 'd' || c == 'e' || c == 'f' || + c == 'A' || c == 'B' || c == 'C' || + c == 'D' || c == 'E' || c == 'F') + tbl[i] = CHAR_HEX_DIGIT; + else if (c == 'x' || c == 'X') + tbl[i] = CHAR_X; + else if (isalpha(c)) + tbl[i] = CHAR_ALPHA; + else if (c == '0') + tbl[i] = CHAR_0; + else if (isdigit(c)) + tbl[i] = CHAR_DIGIT; + else if (c == '\n') + tbl[i] = CHAR_EOL; + else if (c == ' ' || c == '\t') + tbl[i] = CHAR_SPACE; + else if (c == '#') + tbl[i] = CHAR_HASH; + else if (c == '*') + tbl[i] = CHAR_ASTERISK; + else if (c == '.') + tbl[i] = CHAR_DECIMAL; + else if (c == '/') + tbl[i] = CHAR_SLASH; + else if (c == ';' || c == '{' || c == '}') + tbl[i] = CHAR_SPECIAL; + else if (c == '-' || c == '_' || c == '&' || c == '@' || + c == '~') + tbl[i] = CHAR_MISC; + } +} + + +/* + * Get the class of a character. + * + * Arguments: + * c character being scanned + * + * Returns: + * int character class + */ +static int +char_class(c) + char c; +{ + int class = CHAR_INVALID; + + if (c == EOF) { + class = CHAR_EOF; + } else if (c < 0 || !isascii(c)) { + class = CHAR_INVALID; + } else { + class = class_tbl[c]; + } + + return(class); +} + + +/* + * Print an error message when the scanner finds an error + * + * Arguments: + * c character on which the error was recognized + * state scanner state at error + * + * Returns: + * None + */ +static void +scan_error(c, state) + char c; + int state; +{ + /* + * Check for invalid character + */ + if (char_class(c) == CHAR_INVALID) { + parse_error("Invalid character 0x%x encountered", + c); + return; + } + + /* + * Check for unexpected EOF + */ + if (char_class(c) == CHAR_EOF) { + parse_error("Unexpected end of file"); + return; + } + + /* + * Error depends on state + */ + switch(state) { + case TS_INIT: + parse_error("Syntax error at '%c'", c); + break; + case TS_ALPHA: + case TS_INT_1: + case TS_INT: + case TS_SLASH_1: + case TS_COMMENT: + case TS_COMMENT_1: + case TS_FLUSH: + parse_error("Syntax error"); + break; + case TS_HEX: + case TS_HEX_1: + parse_error("Syntax error in hex string"); + break; + } +} + + +/* + * Assemble a token + * + * Read a character at a time from the input file, assembling the + * characters into tokens as specified by the token scanner state + * table. Return the completed token. + * + * Arguments: + * None + * + * Returns: + * token the type of the token found + */ +int +yylex() +{ + int i, state; + char c, token_buffer[TOK_MAX_LEN]; + + /* + * Initialize + */ + if (class_tbl['A'] != CHAR_HEX_DIGIT) + init_class_tbl(class_tbl); + state = TS_INIT; + UM_ZERO(token_buffer, sizeof(token_buffer)); + UM_ZERO(&yylval, sizeof(yylval)); + + /* + * Handle a character at a time until a token is built + */ + while(1) { + /* + * Read a character from the input file. + */ + c = (char)getc(cfg_file); + if (c == '\n') { + parse_line++; + } + +#ifdef NOTDEF + printf("token_state: state=%d, char=%c, class=%d, action=%d, next=%d\n", + state, + c, + char_class(c), + token_state_tbl[char_class][state].action, + token_state_tbl[char_class][state].next); +#endif + + /* + * Perform an action based on the state table + */ + switch(token_state_tbl[char_class(c)][state].action) { + case 0: + /* + * Ignore the character + */ + break; + case 1: + /* + * Add character to buffer + */ + if (strlen(token_buffer) < TOK_MAX_LEN) { + token_buffer[strlen(token_buffer)] = c; + } + break; + case 2: + /* + * Error--print a message and start over + */ + scan_error(c, state); + break; + case 3: + /* + * Return special character + */ + return(c); + break; + case 4: + /* + * Clear the token buffer + */ + UM_ZERO(token_buffer, sizeof(token_buffer)); + break; + case 5: + /* + * Not used + */ + break; + case 6: + /* + * Return character token + */ + push_char(c); + + /* + * Check for reserved words + */ + for (i=0; rsvd_word_tbl[i].word; i++) { + if (strcasecmp(token_buffer, + rsvd_word_tbl[i].word) == 0) + break; + } + if (rsvd_word_tbl[i].word) { + return(rsvd_word_tbl[i].token); + } + + /* + * Word isn't reserved, return alpha string + */ + yylval.tv_alpha = copy_buffer(token_buffer); + return(TOK_NAME); + break; + case 7: + /* + * Return hex string (ATM address) + */ + push_char(c); + yylval.tv_hex = copy_buffer(token_buffer); + return(TOK_HEX); + break; + case 8: + /* + * Return integer + */ + push_char(c); + yylval.tv_int = atoi(token_buffer); + return(TOK_INTEGER); + break; + case 9: + /* + * Return EOF + */ + return(0); + break; + default: + fprintf(stderr, "Invalid action indicator, state=%d, char=0x%02x\n", + state, c); + break; + } + + /* + * Set the next state and bump to the next character + */ + state = token_state_tbl[char_class(c)][state].next; + } +} diff --git a/usr.sbin/atm/scspd/scsp_config_parse.y b/usr.sbin/atm/scspd/scsp_config_parse.y new file mode 100644 index 0000000..4c02de28 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_config_parse.y @@ -0,0 +1,410 @@ +%{ +/* + * + * =================================== + * 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. + * + * @(#) $Id: scsp_config_parse.y,v 1.2 1998/07/24 17:12:14 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * YACC input for configuration file processing + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_config_parse.y,v 1.2 1998/07/24 17:12:14 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" + +#if __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif +%} + + +/* + * Token value definition + */ +%union { + char *tv_alpha; + int tv_int; + char *tv_hex; +} + + +/* + * Token types returned by scanner + */ +%token <tv_alpha> TOK_NAME +%token <tv_int> TOK_INTEGER +%token <tv_hex> TOK_HEX + +/* + * Reserved words + */ +%token TOK_ATMARP +%token TOK_DCS +%token TOK_DCS_ADDR +%token TOK_DCS_CA_REXMIT_INT +%token TOK_DCS_CSUS_REXMIT_INT +%token TOK_DCS_CSU_REXMIT_INT +%token TOK_DCS_CSU_REXMIT_MAX +%token TOK_DCS_HELLO_DF +%token TOK_DCS_HELLO_INT +%token TOK_DCS_HOP_CNT +%token TOK_DCS_ID +%token TOK_DHCP +%token TOK_FAMILY +%token TOK_LFN +%token TOK_LNNI +%token TOK_LOG +%token TOK_MARS +%token TOK_NETIF +%token TOK_NHRP +%token TOK_PROTOCOL +%token TOK_SERVER +%token TOK_SRVGRP +%token TOK_SYSLOG + + +%% +cfg_file: /* Empty */ + | stmt_seq + +stmt_seq: stmt + | stmt_seq stmt + ; + +stmt: server_stmt ';' + | log_stmt ';' + ; + +/* + * SCSP server definition statements + */ +server_stmt: TOK_SERVER TOK_NAME + { + int rc; + + rc = start_server($2); + UM_FREE($2); + if (rc) + return(rc); + } + '{' server_def '}' + { + int rc; + + rc = finish_server(); + if (rc) + return(rc); + } + ; + +server_def: server_spec ';' + | server_def server_spec ';' + ; + +server_spec: /* Nothing */ + | dcs_stmt + | TOK_NETIF TOK_NAME + { + int rc; + + /* + * Configure the network interface + */ + rc = set_intf($2); + UM_FREE($2); + if (rc) + return(rc); + } + | TOK_PROTOCOL TOK_ATMARP + { + int rc; + + /* + * Configure the protocol + */ + rc = set_protocol(SCSP_PROTO_ATMARP); + if (rc) + return(rc); + } + | TOK_PROTOCOL TOK_DHCP | TOK_LNNI | TOK_MARS | TOK_NHRP + { + yyerror("Protocol not implemented"); + return(1); + } + | TOK_SRVGRP TOK_INTEGER + { + int rc; + + /* + * Configure the SCSP server group ID + */ + rc = set_server_group($2); + if (rc) + return(rc); + } + ; + +/* + * SCSP DCS definition statements + */ +dcs_stmt: TOK_DCS + { + int rc; + + rc = start_dcs(); + if (rc) + return(rc); + } + '{' dcs_def '}' + { + int rc; + + rc = finish_dcs(); + if (rc) + return(rc); + } + ; + +dcs_def: dcs_spec ';' + | dcs_def dcs_spec ';' + ; + +dcs_spec: /* Nothing */ + | TOK_DCS_ADDR TOK_HEX + { + int rc; + + /* + * Set DCS address + */ + rc = set_dcs_addr($2, (char *)0); + UM_FREE($2); + if (rc) + return(rc); + } + | TOK_DCS_ADDR TOK_HEX TOK_HEX + { + int rc; + + /* + * Set DCS address and subaddress + */ + rc = set_dcs_addr($2, $3); + UM_FREE($2); + UM_FREE($3); + if (rc) + return(rc); + } + | TOK_DCS_CA_REXMIT_INT TOK_INTEGER + { + int rc; + + /* + * Configure the CA retransmit interval + */ + rc = set_dcs_ca_rexmit($2); + if (rc) + return(rc); + } + | TOK_DCS_CSUS_REXMIT_INT TOK_INTEGER + { + int rc; + + /* + * Configure the CSUS retransmit interval + */ + rc = set_dcs_csus_rexmit($2); + if (rc) + return(rc); + } + | TOK_DCS_CSU_REXMIT_INT TOK_INTEGER + { + int rc; + + /* + * Configure the CSU retransmit interval + */ + rc = set_dcs_csu_rexmit($2); + if (rc) + return(rc); + } + | TOK_DCS_CSU_REXMIT_MAX TOK_INTEGER + { + int rc; + + /* + * Configure the CSU retransmit limit + */ + rc = set_dcs_csu_rexmit_max($2); + if (rc) + return(rc); + } + | TOK_DCS_HELLO_DF TOK_INTEGER + { + int rc; + + /* + * Configure the Hello dead factor + */ + rc = set_dcs_hello_df($2); + if (rc) + return(rc); + } + | TOK_DCS_HELLO_INT TOK_INTEGER + { + int rc; + + /* + * Configure the Hello interval + */ + rc = set_dcs_hello_int($2); + if (rc) + return(rc); + } + | TOK_DCS_HOP_CNT TOK_INTEGER + { + int rc; + + /* + * Configure the hop count + */ + rc = set_dcs_hops($2); + if (rc) + return(rc); + } + | TOK_DCS_ID TOK_NAME + { + int rc; + + /* + * Configure the DCS ID + */ + rc = set_dcs_id($2); + UM_FREE($2); + if (rc) + return(rc); + } + ; + + +/* + * Logging option statements + */ +log_stmt: TOK_LOG + '{' log_spec '}' + ; + +log_spec: /* Nothing */ + | TOK_LFN TOK_NAME ';' + { + /* + * Configure the log file name + */ + int rc; + + rc = set_log_file($2); + UM_FREE($2); + if (rc) + return(rc); + } + ; + | TOK_SYSLOG ';' + { + /* + * Configure logging to syslog + */ + scsp_log_syslog = 1; + } + ; + +%% + +void +#if __STDC__ +parse_error(const char *fmt, ...) +#else +parse_error(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; + char buff[256]; + +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + + vsprintf(buff, fmt, ap); + scsp_log(LOG_ERR, "%s: Config file error at line %d: %s\n", + prog, parse_line, buff); +#ifdef NOTDEF + fprintf(stderr, "%s: Config file error at line %d: %s\n", + prog, parse_line, buff); +#endif + va_end(ap); +} + + +yyerror(s) + char *s; +{ + parse_error(s); +} diff --git a/usr.sbin/atm/scspd/scsp_hfsm.c b/usr.sbin/atm/scspd/scsp_hfsm.c new file mode 100644 index 0000000..2953804 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_hfsm.c @@ -0,0 +1,580 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: scsp_hfsm.c,v 1.4 1998/07/16 15:59:25 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * HELLO finite state machine + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_hfsm.c,v 1.4 1998/07/16 15:59:25 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" + + +/* + * HELLO FSM actions + */ +#define HELLO_ACTION_CNT 7 +int scsp_hello_act_00 __P((Scsp_dcs *, Scsp_msg *)); +int scsp_hello_act_01 __P((Scsp_dcs *, Scsp_msg *)); +int scsp_hello_act_02 __P((Scsp_dcs *, Scsp_msg *)); +int scsp_hello_act_03 __P((Scsp_dcs *, Scsp_msg *)); +int scsp_hello_act_04 __P((Scsp_dcs *, Scsp_msg *)); +int scsp_hello_act_05 __P((Scsp_dcs *, Scsp_msg *)); +int scsp_hello_act_06 __P((Scsp_dcs *, Scsp_msg *)); + +static int (*scsp_action_vector[HELLO_ACTION_CNT])() = { + scsp_hello_act_00, + scsp_hello_act_01, + scsp_hello_act_02, + scsp_hello_act_03, + scsp_hello_act_04, + scsp_hello_act_05, + scsp_hello_act_06 +}; + +/* + * HELLO FSM state table + */ +static int hello_state_table[SCSP_HFSM_EVENT_CNT][SCSP_HFSM_STATE_CNT] = { + /* 0 1 2 3 */ + { 1, 1, 1, 1 }, /* 0 */ + { 0, 2, 2, 2 }, /* 1 */ + { 0, 3, 3, 3 }, /* 2 */ + { 0, 0, 4, 4 }, /* 3 */ + { 0, 5, 5, 6 }, /* 4 */ +}; + +/* + * HELLO finite state machine + * + * Arguments: + * dcsp pointer to a DCS control block for the neighbor + * event the event which has occurred + * msg pointer to received message, if there is one + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_hfsm(dcsp, event, msg) + Scsp_dcs *dcsp; + int event; + Scsp_msg *msg; +{ + int action, rc, state; + + /* + * Select an action from the state table + */ + state = dcsp->sd_hello_state; + action = hello_state_table[event][state]; + if (scsp_trace_mode & SCSP_TRACE_HFSM) { + scsp_trace("HFSM: state=%d, event=%d, action=%d\n", + state, event, action); + } + if (action >= HELLO_ACTION_CNT || action <= 0) { + scsp_log(LOG_ERR, "Hello FSM--invalid action %d; state=%d, event=%d", + action, dcsp->sd_hello_state, event); + abort(); + } + + /* + * Perform the selected action + */ + rc = scsp_action_vector[action](dcsp, msg); + + return(rc); +} + + +/* + * HELLO finite state machine action 0 + * Unexpected action -- log an error message + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to received message (ignored) + * + * Returns: + * EOPNOTSUPP always returns EOPNOTSUPP + * + */ +int +scsp_hello_act_00(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + scsp_log(LOG_ERR, "Hello FSM error--unexpected action, state=%d", + dcsp->sd_hello_state); + return(EOPNOTSUPP); +} + + +/* + * HELLO finite state machine action 1 + * VCC open -- send HELLO message, start hello timer, go to Waiting + * state + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to received message (ignored) + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_hello_act_01(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + int rc; + + /* + * Cancel the VCC open timer if it's running + */ + HARP_CANCEL(&dcsp->sd_open_t); + + /* + * Go to Waiting state + */ + dcsp->sd_hello_state = SCSP_HFSM_WAITING; + + /* + * Send a Hello message + */ + rc = scsp_send_hello(dcsp); + if (rc == 0) { + /* + * Success--start the Hello timer + */ + HARP_TIMER(&dcsp->sd_hello_h_t, SCSP_HELLO_Interval, + scsp_hello_timeout); + } + + return(rc); +} + + +/* + * HELLO finite state machine action 2 + * VCC closed -- notify CA FSM, go to Down state, try to re-open VCC + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to received message (ignored) + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_hello_act_02(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + int rc; + struct in_addr addr; + + /* + * Cancel any current timers + */ + HARP_CANCEL(&dcsp->sd_hello_h_t); + HARP_CANCEL(&dcsp->sd_hello_rcv_t); + + /* + * Log the loss of the VCC + */ + if (dcsp->sd_hello_state > SCSP_HFSM_WAITING) { + scsp_log(LOG_ERR, "VC to %s closed", + format_atm_addr(&dcsp->sd_addr)); + } + + /* + * Tell the CA FSM that the conection to the DCS is lost + */ + rc = scsp_cafsm(dcsp, SCSP_CAFSM_HELLO_DOWN, (void *)0); + + /* + * Go to Down state + */ + dcsp->sd_hello_state = SCSP_HFSM_DOWN; + + /* + * If our ID is lower than the DCS's, wait a second before + * trying to connect. This should keep both of us from + * trying to connect at the same time, resulting in two + * VCCs being open. + */ + if (scsp_cmp_id(&dcsp->sd_server->ss_lsid, + &dcsp->sd_dcsid) < 0) { + /* + * Our ID is lower--start the VCC open timer for one + * second so we'll try to open the VCC if the DCS + * doesn't do it by then + */ + HARP_TIMER(&dcsp->sd_open_t, 1, scsp_open_timeout); + } else { + /* + * Our ID is higher--try to reopen the VCC immediately + */ + if (scsp_dcs_connect(dcsp)) { + /* + * Conncect failed -- set a timer and try + * again later + */ + HARP_TIMER(&dcsp->sd_open_t, SCSP_Open_Interval, + scsp_open_timeout); + } + } + + return(0); +} + + +/* + * HELLO finite state machine action 3 + * Hello timer expired -- send HELLO message, restart hello timer + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to received message (ignored) + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_hello_act_03(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + int rc; + + /* + * Send a Hello message + */ + rc = scsp_send_hello(dcsp); + if (rc == 0) { + /* + * Success--restart the Hello timer + */ + HARP_TIMER(&dcsp->sd_hello_h_t, SCSP_HELLO_Interval, + scsp_hello_timeout); + } + + return(rc); +} + + +/* + * HELLO finite state machine action 4 + * Receive timer expired -- if we haven't received any Hellos, notify + * CA FSM and go to Waiting state; if we've received Hellos, but we + * weren't in the receiver ID list, go to Unidirectional state + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to received message (ignored) + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_hello_act_04(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + int rc = 0; + + /* + * Check whether we'ver received any Hellos lately + */ + if (dcsp->sd_hello_rcvd) { + /* + * We've had Hellos since the receive timer was + * started--go to Unidirectional state + */ + dcsp->sd_hello_rcvd = 0; + dcsp->sd_hello_state = SCSP_HFSM_UNI_DIR; + } else { + /* + * We haven't seen any Hellos at all from the DCS in + * hello_interval * dead_factor seconds--go to Waiting + * state + */ + dcsp->sd_hello_state = SCSP_HFSM_WAITING; + } + + /* + * Notify the CA FSM + */ + rc = scsp_cafsm(dcsp, SCSP_CAFSM_HELLO_DOWN, (void *)0); + + return(rc); +} + + +/* + * HELLO finite state machine action 5 + * Message received -- Ignore all but HELLO messages; if local server + * is in receiver list, notify CA FSM and go to Bidirectional state; + * otherwise, go to Unidirectional state + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to received message + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_hello_act_05(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + int rc; + Scsp_id *ridp; + + /* + * Null message pointer means message decode failed, so + * message must have been invalid. Go to Waiting state. + */ + if (msg == (Scsp_msg *)0) { + dcsp->sd_hello_state = SCSP_HFSM_WAITING; + HARP_CANCEL(&dcsp->sd_hello_rcv_t); + return(0); + } + + /* + * Ignore the message if it isn't a Hello + */ + if (msg->sc_msg_type != SCSP_HELLO_MSG) { + return(0); + } + + /* + * Save relevant information about DCS, but don't let him give + * us zero for timeout values + */ + if (msg->sc_hello->hello_int) { + dcsp->sd_hello_int = msg->sc_hello->hello_int; + } else { + dcsp->sd_hello_int = 1; + } + if (msg->sc_hello->dead_factor) { + dcsp->sd_hello_df = msg->sc_hello->dead_factor; + } else { + dcsp->sd_hello_df = 1; + } + dcsp->sd_dcsid = msg->sc_hello->hello_mcp.sid; + + /* + * Check the message for the local server's ID + */ + for (ridp = &msg->sc_hello->hello_mcp.rid; + ridp; + ridp = ridp->next) { + if (scsp_cmp_id(&dcsp->sd_server->ss_lsid, ridp) == 0) { + /* + * Cancel and restart the receive timer + */ + HARP_CANCEL(&dcsp->sd_hello_rcv_t); + HARP_TIMER(&dcsp->sd_hello_rcv_t, + dcsp->sd_hello_int * dcsp->sd_hello_df, + scsp_hello_rcv_timeout); + + /* + * Go to Bidirectional state and notify the + * CA FSM that the connection is up + */ + dcsp->sd_hello_state = SCSP_HFSM_BI_DIR; + rc = scsp_cafsm(dcsp, + SCSP_CAFSM_HELLO_UP, + (void *)0); + return(rc); + } + } + + /* + * We weren't in the receiver ID list, so go to + * Unidirectional state + */ + dcsp->sd_hello_state = SCSP_HFSM_UNI_DIR; + + return(0); +} + + +/* + * HELLO finite state machine action 6 + * Message received -- if message is not a HELLO, pass it to the CA + * FSM; otherwise, if local server is not in receiver list, notify + * CA FSM and go to Unidirectional state + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to received message + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_hello_act_06(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + int rc, rcv_found; + Scsp_id *ridp; + + /* + * Null message pointer means message decode failed, so + * message must have been invalid. Go to Waiting state. + */ + if (msg == (Scsp_msg *)0) { + HARP_CANCEL(&dcsp->sd_hello_rcv_t); + dcsp->sd_hello_state = SCSP_HFSM_WAITING; + rc = scsp_cafsm(dcsp, SCSP_CAFSM_HELLO_DOWN, (void *)0); + return(rc); + } + + /* + * Process the message depending on its type + */ + switch(msg->sc_msg_type) { + case SCSP_CA_MSG: + rc = scsp_cafsm(dcsp, SCSP_CAFSM_CA_MSG, (void *)msg); + break; + case SCSP_CSU_REQ_MSG: + rc = scsp_cafsm(dcsp, SCSP_CAFSM_CSU_REQ, (void *)msg); + break; + case SCSP_CSU_REPLY_MSG: + rc = scsp_cafsm(dcsp, SCSP_CAFSM_CSU_REPLY, + (void *)msg); + break; + case SCSP_CSUS_MSG: + rc = scsp_cafsm(dcsp, SCSP_CAFSM_CSUS_MSG, (void *)msg); + break; + case SCSP_HELLO_MSG: + /* + * Make sure DCS info is consistent. The sender ID, + * family ID, protocol ID, and server group ID are + * checked. + */ + if (scsp_cmp_id(&msg->sc_hello->hello_mcp.sid, + &dcsp->sd_dcsid) || + (msg->sc_hello->family_id != + dcsp->sd_server->ss_fid) || + (msg->sc_hello->hello_mcp.pid != + dcsp->sd_server->ss_pid) || + (msg->sc_hello->hello_mcp.sgid != + dcsp->sd_server->ss_sgid)) { + /* + * Bad info--revert to waiting state + */ + HARP_CANCEL(&dcsp->sd_hello_rcv_t); + dcsp->sd_hello_state = SCSP_HFSM_WAITING; + rc = scsp_cafsm(dcsp, + SCSP_CAFSM_HELLO_DOWN, + (void *)0); + return(rc); + } + + /* + * Mark the arrival of the Hello message + */ + dcsp->sd_hello_rcvd = 1; + + /* + * Check the message for the local server's ID + */ + rc = 0; + for (ridp = &msg->sc_hello->hello_mcp.rid, + rcv_found = 0; + ridp; + ridp = ridp->next) { + rcv_found = (scsp_cmp_id(ridp, + &dcsp->sd_server->ss_lsid) == 0); + } + + if (rcv_found) { + /* + * The LS ID was in the list of receiver IDs-- + * Reset the Hello receive timer + */ + dcsp->sd_hello_rcvd = 0; + HARP_CANCEL(&dcsp->sd_hello_rcv_t); + HARP_TIMER(&dcsp->sd_hello_rcv_t, + dcsp->sd_hello_int * + dcsp->sd_hello_df, + scsp_hello_rcv_timeout); + } + break; + } + + return(rc); +} diff --git a/usr.sbin/atm/scspd/scsp_if.c b/usr.sbin/atm/scspd/scsp_if.c new file mode 100644 index 0000000..1930990 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_if.c @@ -0,0 +1,655 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: scsp_if.c,v 1.5 1998/08/13 20:11:14 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * Interface to client server protocol + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_if.c,v 1.5 1998/08/13 20:11:14 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" + + +/* + * SCSP client server interface FSM actions + */ +#define SCSP_CIFSM_ACTION_CNT 11 +int scsp_client_act_00 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_01 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_02 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_03 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_04 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_05 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_06 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_07 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_08 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_09 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); +int scsp_client_act_10 + __P((Scsp_dcs *, Scsp_msg *, Scsp_if_msg *)); + +static int (*scsp_action_vector[SCSP_CIFSM_ACTION_CNT])() = { + scsp_client_act_00, + scsp_client_act_01, + scsp_client_act_02, + scsp_client_act_03, + scsp_client_act_04, + scsp_client_act_05, + scsp_client_act_06, + scsp_client_act_07, + scsp_client_act_08, + scsp_client_act_09, + scsp_client_act_10 +}; + + +/* + * Client server interface FSM state table + */ +static int client_state_table[SCSP_CIFSM_EVENT_CNT][SCSP_CIFSM_STATE_CNT] = { + /* 0 1 2 3 */ + { 1, 3, 3, 3 }, /* 0 */ + { 2, 5, 5, 5 }, /* 1 */ + { 0, 4, 0, 0 }, /* 2 */ + { 0, 6, 6, 1 }, /* 3 */ + { 1, 0, 7, 7 }, /* 4 */ + { 7, 7, 7, 7 }, /* 5 */ + { 1, 1, 8, 8 }, /* 6 */ + { 0, 0, 10, 10 }, /* 7 */ + { 0, 0, 1, 1 }, /* 8 */ + { 0, 0, 9, 9 } /* 9 */ +}; + + +/* + * SCSP client server interface finite state machine + * + * Arguments: + * ssp pointer to server control block + * event the event which has occurred + * msg pointer to message from DCS, if there is one + * cmsg pointer to message from server, if there is one + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_cfsm(dcsp, event, msg, cmsg) + Scsp_dcs *dcsp; + int event; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + int action, rc, state; + + /* + * Select an action from the state table + */ + state = dcsp->sd_client_state; + action = client_state_table[event][state]; + if (scsp_trace_mode & SCSP_TRACE_CFSM) { + scsp_trace("Server I/F FSM: state=%d, event=%d, action=%d\n", + state, event, action); + } + if (action >= SCSP_CIFSM_ACTION_CNT || action <= 0) { + scsp_log(LOG_ERR, "Server I/F FSM--invalid action %d; state=%d, event=%d", + action, dcsp->sd_client_state, event); + exit(1); + } + + /* + * Perform the selected action + */ + rc = scsp_action_vector[action](dcsp, msg, cmsg); + + return(rc); +} + + +/* + * SCSP client server interface finite state machine action 0 + * Unexpected action -- log an error message + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS (ignored) + * cmsg pointer to message from server (ignored) + * + * Returns: + * EOPNOTSUPP always returns EOPNOTSUPP + * + */ +int +scsp_client_act_00(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + scsp_log(LOG_ERR, "Server I/F FSM error--unexpected action, state=%d", + dcsp->sd_client_state); + return(EOPNOTSUPP); +} + + +/* + * SCSP client server interface finite state machine action 1 + * + * Ignore an event + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 always returns 0 + * + */ +int +scsp_client_act_01(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + return(0); +} + + +/* + * SCSP client server interface finite state machine action 2 + * + * CA FSM went to Cache Summarize state--go to Summarize + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 success + * else errno describing error + * + */ +int +scsp_client_act_02(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + /* + * Set the new state + */ + dcsp->sd_client_state = SCSP_CIFSM_SUM; + + return(0); +} + + +/* + * SCSP client server interface finite state machine action 3 + * + * CA FSM went down--clean up and go to Null + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 success + * else errno describing error + * + */ +int +scsp_client_act_03(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + /* + * Set the new state + */ + dcsp->sd_client_state = SCSP_CIFSM_NULL; + + return(0); +} + + +/* + * SCSP client server interface finite state machine action 4 + * + * CA FSM went to Update Cache state--go to Update state + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 success + * else errno describing error + * + */ +int +scsp_client_act_04(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + /* + * Set the new state + */ + dcsp->sd_client_state = SCSP_CIFSM_UPD; + + return(0); +} + + +/* + * SCSP client server interface finite state machine action 5 + * + * The CA FSM went to Cache Summarize state from Summarize, + * Update, or Aligned, implying that the CA FSM went down and came + * back up--copy the server's cache to the DCSs CSAS list and go to + * Summarize state + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 success + * else errno describing error + * + */ +int +scsp_client_act_05(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + int i, rc; + Scsp_cse *csep, *ncsep; + + /* + * Copy the cache summmary to the CSAS list + */ + for (i = 0; i < SCSP_HASHSZ; i++) { + for (csep = dcsp->sd_server->ss_cache[i]; csep; + csep = csep->sc_next) { + ncsep = scsp_dup_cse(csep); + LINK2TAIL(ncsep, Scsp_cse, dcsp->sd_ca_csas, + sc_next); + } + } + + /* + * Set the new state + */ + dcsp->sd_client_state = SCSP_CIFSM_SUM; + + return(0); + +act_05_fail: + for (csep = dcsp->sd_ca_csas; csep; csep = ncsep) { + ncsep = csep->sc_next; + UNLINK(csep, Scsp_cse, dcsp->sd_ca_csas, sc_next); + UM_FREE(csep); + } + + dcsp->sd_client_state = SCSP_CIFSM_NULL; + + return(rc); +} + + +/* + * SCSP client server interface finite state machine action 6 + * + * CA FSM went to Aligned state--go to Aligned + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 success + * else errno describing error + * + */ +int +scsp_client_act_06(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + /* + * Set the new state + */ + dcsp->sd_client_state = SCSP_CIFSM_ALIGN; + + return(0); +} + + +/* + * SCSP client server interface finite state machine action 7 + * + * We received a Solicit Rsp or Update Req from the server--pass it + * to the CA FSM + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 success + * else errno describing error + * + */ +int +scsp_client_act_07(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + int rc; + Scsp_csa *csap; + Scsp_atmarp_csa *acp; + + /* + * Allocate memory for a CSA record + */ + csap = (Scsp_csa *)UM_ALLOC(sizeof(Scsp_csa)); + if (!csap) { + scsp_mem_err("scsp_client_act_07: sizeof(Scsp_csa)"); + } + acp = (Scsp_atmarp_csa *)UM_ALLOC(sizeof(Scsp_atmarp_csa)); + if (!acp) { + scsp_mem_err("scsp_client_act_07: sizeof(Scsp_atmarp_csa)"); + } + UM_ZERO(csap, sizeof(Scsp_csa)); + UM_ZERO(acp, sizeof(Scsp_atmarp_csa)); + + /* + * Build a CSA record from the server's message + */ + csap->hops = dcsp->sd_hops; + csap->null = (cmsg->si_atmarp.sa_state == SCSP_ASTATE_DEL) || + (cmsg->si_type == SCSP_SOLICIT_RSP && + cmsg->si_rc != SCSP_RSP_OK); + csap->seq = cmsg->si_atmarp.sa_seq; + csap->key = cmsg->si_atmarp.sa_key; + csap->oid = cmsg->si_atmarp.sa_oid; + csap->atmarp_data = acp; + acp->sa_state = cmsg->si_atmarp.sa_state; + acp->sa_sha = cmsg->si_atmarp.sa_cha; + acp->sa_ssa = cmsg->si_atmarp.sa_csa; + acp->sa_spa = cmsg->si_atmarp.sa_cpa; + acp->sa_tpa = cmsg->si_atmarp.sa_cpa; + + /* + * Call the CA FSM + */ + rc = scsp_cafsm(dcsp, SCSP_CAFSM_CACHE_UPD, (void *)csap); + + return(rc); +} + + +/* + * SCSP client server interface finite state machine action 8 + * + * Update Rsp from server--pass the update to the CA FSM. + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 success + * else errno describing error + * + */ +int +scsp_client_act_08(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + int rc; + + /* + * Pass the response to the CA FSM + */ + switch (dcsp->sd_server->ss_pid) { + case SCSP_PROTO_ATMARP: + rc = scsp_cafsm(dcsp, SCSP_CAFSM_CACHE_RSP, cmsg); + break; + default: + rc = EPROTONOSUPPORT; + } + + return(rc); +} + + +/* + * SCSP client server interface finite state machine action 9 + * + * CSU Solicit from DCS--pass Solicit Ind to server + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 success + * else errno describing error + * + */ +int +scsp_client_act_09(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + int rc, rrc = 0; + Scsp_csa *csap; + Scsp_if_msg *csip; + + /* + * Get memory for a Solicit Ind + */ + csip = (Scsp_if_msg *)UM_ALLOC(sizeof(Scsp_if_msg)); + if (!csip) { + scsp_mem_err("scsp_client_act_09: sizeof(Scsp_if_msg)"); + } + + /* + * Loop through list of CSAs + */ + for (csap = msg->sc_csu_msg->csu_csa_rec; csap; + csap = csap->next) { + /* + * Fill out the Solicit Indication + */ + UM_ZERO(csip, sizeof(Scsp_if_msg)); + csip->si_type = SCSP_SOLICIT_IND; + csip->si_proto = dcsp->sd_server->ss_pid; + csip->si_tok = (u_long)dcsp; + csip->si_len = sizeof(Scsp_if_msg_hdr) + + sizeof(Scsp_sum_msg); + csip->si_sum.ss_hops = csap->hops; + csip->si_sum.ss_null = csap->null; + csip->si_sum.ss_seq = csap->seq; + csip->si_sum.ss_key = csap->key; + csip->si_sum.ss_oid = csap->oid; + + /* + * Send the Solicit Ind to the server + */ + rc = scsp_if_sock_write(dcsp->sd_server->ss_sock, csip); + if (rc) { + rrc = rc; + } + } + + UM_FREE(csip); + return(rrc); +} + + +/* + * SCSP client server interface finite state machine action 10 + * + * CSU Request from DCS--pass it to the server as a Cache Update + * Indication + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message from DCS + * cmsg pointer to message from server + * + * Returns: + * 0 success + * else errno describing error + * + */ +int +scsp_client_act_10(dcsp, msg, cmsg) + Scsp_dcs *dcsp; + Scsp_msg *msg; + Scsp_if_msg *cmsg; +{ + int rc, rrc = 0; + Scsp_csa *csap; + Scsp_atmarp_csa *acp; + Scsp_if_msg *cuip; + + /* + * Get memory for a Cache Update Ind + */ + cuip = (Scsp_if_msg *)UM_ALLOC(sizeof(Scsp_if_msg)); + if (!cuip) { + scsp_mem_err("scsp_client_act_10: sizeof(Scsp_if_msg)"); + } + + /* + * Loop through CSAs in message + */ + for (csap = msg->sc_csu_msg->csu_csa_rec; csap; + csap = csap->next) { + acp = csap->atmarp_data; + if (!acp) + continue; + + /* + * Fill out the Cache Update Ind + */ + UM_ZERO(cuip, sizeof(Scsp_if_msg)); + cuip->si_type = SCSP_UPDATE_IND; + cuip->si_proto = dcsp->sd_server->ss_pid; + cuip->si_tok = (u_long)dcsp; + switch(dcsp->sd_server->ss_pid) { + case SCSP_PROTO_ATMARP: + cuip->si_len = sizeof(Scsp_if_msg_hdr) + + sizeof(Scsp_atmarp_msg); + cuip->si_atmarp.sa_state = acp->sa_state; + cuip->si_atmarp.sa_cpa = acp->sa_spa; + cuip->si_atmarp.sa_cha = acp->sa_sha; + cuip->si_atmarp.sa_csa = acp->sa_ssa; + cuip->si_atmarp.sa_key = csap->key; + cuip->si_atmarp.sa_oid = csap->oid; + cuip->si_atmarp.sa_seq = csap->seq; + break; + case SCSP_PROTO_NHRP: + /* + * Not implemented yet + */ + break; + } + + /* + * Send the Cache Update Ind to the server + */ + rc = scsp_if_sock_write(dcsp->sd_server->ss_sock, cuip); + if (rc) { + rrc = rc; + } + } + + UM_FREE(cuip); + return(rrc); +} diff --git a/usr.sbin/atm/scspd/scsp_if.h b/usr.sbin/atm/scspd/scsp_if.h new file mode 100644 index 0000000..dde3407 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_if.h @@ -0,0 +1,194 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: scsp_if.h,v 1.2 1998/07/16 15:59:33 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * Interface to server clients of SCSP + * + */ + +#ifndef _SCSP_SCSP_IF_H +#define _SCSP_SCSP_IF_H + + +/* + * SCSP configuration message + */ +struct scsp_cfg_msg { + char atmarp_netif[IFNAMSIZ]; +}; +typedef struct scsp_cfg_msg Scsp_cfg_msg; + + +/* + * SCSP cache summary + */ +struct scsp_sum_msg { + u_short ss_hops; /* Hop count */ + u_char ss_null; /* Null flag */ + long ss_seq; /* CSA seq. no. */ + Scsp_ckey ss_key; /* Cache key */ + Scsp_id ss_oid; /* Originator ID */ +}; +typedef struct scsp_sum_msg Scsp_sum_msg; + + +/* + * SCSP constants for ATMARP + */ +#define SCSP_ATMARP_PROTO 1 +#define SCSP_ATMARP_SIDL 4 +#define SCSP_ATMARP_RIDL 4 +#define SCSP_ATMARP_CKL 4 +#define SCSP_ATMARP_OIDL 4 + + +/* + * SCSP ATMARP message + */ +struct scsp_atmarp_msg { + u_char sa_state; /* Cache entry state (below) */ + struct in_addr sa_cpa; /* Cached protocol address */ + Atm_addr sa_cha; /* Cached ATM address */ + Atm_addr sa_csa; /* Cached ATM subaddress */ + Scsp_ckey sa_key; /* Cache key for entry */ + Scsp_id sa_oid; /* Originator ID */ + long sa_seq; /* Sequence no. */ +}; +typedef struct scsp_atmarp_msg Scsp_atmarp_msg; + +#define SCSP_ASTATE_NEW 0 /* ATMARP new server registration */ +#define SCSP_ASTATE_UPD 1 /* ATMARP server refreshed */ +#define SCSP_ASTATE_DEL 2 /* ATMARP server data deleted */ + + +/* + * SCSP constants for NHRP + */ +#define SCSP_NHRP_PROTO 2 +#define SCSP_NHRP_SIDL 4 +#define SCSP_NHRP_RIDL 4 +#define SCSP_NHRP_CKL 4 +#define SCSP_NHRP_OIDL 4 + + +/* + * SCSP NHRP message + */ +struct scsp_nhrp_msg { + u_short sn_af; /* Address family */ + u_short sn_proto; /* NHRP protocol type */ + u_char sn_snap[5]; /* SNAP */ + u_char sn_ver; /* NHRP version number */ + u_short sn_flags; /* Flags */ + u_long sn_rid; /* Request ID */ + u_char sn_state; /* State */ + u_char sn_prel; /* Prefix length */ + u_short sn_mtu; /* Maximum transmission unit */ + u_short sn_hold; /* Holding time */ + Atm_addr sn_addr; /* Server network address */ + Atm_addr sn_saddr; /* Server network subaddress */ + struct in_addr sn_paddr; /* Server protocol address */ + Scsp_ckey sn_key; /* Cache key for entry */ + Scsp_id sn_oid; /* Originator ID */ +}; +typedef struct scsp_nhrp_msg Scsp_nhrp_msg; + +#define SCSP_NSTATE_NEW 0 /* New NHRP server */ +#define SCSP_NSTATE_UPD 1 /* NHRP server re-registered */ +#define SCSP_NSTATE_DEL 2 /* NHRP server data purged */ +#define SCSP_NSTATE_NSD 3 /* NHRP no such data in server */ + + +/* + * SCSP/server message header + */ +struct scsp_if_msg_hdr { + u_char sh_type; /* Message type */ + u_char sh_rc; /* Response code */ + u_short sh_proto; /* SCSP protocol ID */ + int sh_len; /* Length of message */ + u_long sh_tok; /* Token from SCSP daemon */ +}; +typedef struct scsp_if_msg_hdr Scsp_if_msg_hdr; + + +/* + * SCSP-server message + */ +struct scsp_if_msg { + Scsp_if_msg_hdr si_hdr; /* Header fields */ + union { + Scsp_cfg_msg siu_cfg; /* Config data */ + Scsp_sum_msg siu_sum; /* Cache summary */ + Scsp_atmarp_msg siu_atmarp; /* ATMARP update */ + Scsp_nhrp_msg siu_nhrp; /* NHRP update */ + } si_u; +}; +typedef struct scsp_if_msg Scsp_if_msg; + +#define si_type si_hdr.sh_type +#define si_rc si_hdr.sh_rc +#define si_proto si_hdr.sh_proto +#define si_len si_hdr.sh_len +#define si_tok si_hdr.sh_tok + +#define si_cfg si_u.siu_cfg +#define si_sum si_u.siu_sum +#define si_atmarp si_u.siu_atmarp +#define si_nhrp si_u.siu_nhrp + + +/* + * Message types + */ +#define SCSP_NOP_REQ 1 +#define SCSP_CFG_REQ 2 +#define SCSP_CFG_RSP 3 +#define SCSP_CACHE_IND 4 +#define SCSP_CACHE_RSP 5 +#define SCSP_SOLICIT_IND 6 +#define SCSP_SOLICIT_RSP 7 +#define SCSP_UPDATE_IND 8 +#define SCSP_UPDATE_REQ 9 +#define SCSP_UPDATE_RSP 10 + + +/* + * Response codes + */ +#define SCSP_RSP_OK 0 +#define SCSP_RSP_ERR 1 +#define SCSP_RSP_REJ 2 +#define SCSP_RSP_NOT_FOUND 3 + + +#endif /* _SCSP_SCSP_IF_H */ diff --git a/usr.sbin/atm/scspd/scsp_input.c b/usr.sbin/atm/scspd/scsp_input.c new file mode 100644 index 0000000..21d0a07 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_input.c @@ -0,0 +1,1103 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: scsp_input.c,v 1.3 1998/08/13 20:11:15 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * Input packet processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_input.c,v 1.3 1998/08/13 20:11:15 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" + + +static int scsp_parse_atmarp __P((char *, int, Scsp_atmarp_csa **)); + + +/* + * Get a long ingeter + * + * This routine is provided to handle long integers that may not + * be word-aligned in the input buffer. + * + * Arguments: + * cp pointer to long int in message + * + * Returns: + * int long int in host order + * + */ +static u_long +get_long(cp) + u_char *cp; +{ + int i; + u_long l; + + /* + * Read the long out of the input buffer + */ + l = 0; + for (i = 0; i < sizeof(u_long); i++) + l = (l << 8) + *cp++; + + /* + * Return the value in host order + */ + return(l); +} + + +/* + * Free an SCSP Cache Alignment message in internal format + * + * Arguments: + * cap pointer to CA message + * + * Returns: + * None + * + */ +static void +scsp_free_ca(cap) + Scsp_ca *cap; +{ + Scsp_csa *csap, *ncsap; + + /* + * Return if there's nothing to free + */ + if (cap == (Scsp_ca *)0) + return; + + /* + * Free the CSAS records + */ + for (csap = cap->ca_csa_rec; csap; csap = ncsap) { + ncsap = csap->next; + SCSP_FREE_CSA(csap); + } + /* + * Free the CA message structure + */ + UM_FREE(cap); +} + + +/* + * Free an SCSP Cache State Update Request, Cache State Update Reply, + * or Cache State Update Solicit message in internal format + * + * Arguments: + * csup pointer to CSU message + * + * Returns: + * None + * + */ +static void +scsp_free_csu(csup) + Scsp_csu_msg *csup; +{ + Scsp_csa *csap, *ncsap; + + /* + * Return if there's nothing to free + */ + if (csup == (Scsp_csu_msg *)0) + return; + + /* + * Free the CSA records + */ + for (csap = csup->csu_csa_rec; csap; csap = ncsap) { + ncsap = csap->next; + SCSP_FREE_CSA(csap); + } + + /* + * Free the CSU message structure + */ + UM_FREE(csup); +} + + +/* + * Free an SCSP Hello message in internal format + * + * Arguments: + * hp pointer to Hello message + * + * Returns: + * None + * + */ +static void +scsp_free_hello(hp) + Scsp_hello *hp; +{ + /* + * Return if there's nothing to free + */ + if (hp == (Scsp_hello *)0) + return; + + /* + * Free the Hello message structure + */ + UM_FREE(hp); +} + + +/* + * Free an SCSP message in internal format + * + * Arguments: + * msg pointer to input packet + * + * Returns: + * None + * + */ +void +scsp_free_msg(msg) + Scsp_msg *msg; +{ + Scsp_ext *exp, *nexp; + + /* + * Return if there's nothing to free + */ + if (msg == (Scsp_msg *)0) + return; + + /* + * Free the message body + */ + switch(msg->sc_msg_type) { + case SCSP_CA_MSG: + scsp_free_ca(msg->sc_ca); + break; + case SCSP_CSU_REQ_MSG: + case SCSP_CSU_REPLY_MSG: + case SCSP_CSUS_MSG: + scsp_free_csu(msg->sc_csu_msg); + break; + case SCSP_HELLO_MSG: + scsp_free_hello(msg->sc_hello); + break; + } + + /* + * Free any extensions + */ + for (exp = msg->sc_ext; exp; exp = nexp) { + nexp = exp->next; + UM_FREE(exp); + } + + /* + * Free the message structure + */ + UM_FREE(msg); +} + + +/* + * Parse a Sender or Receiver ID + * + * Arguments: + * buff pointer to ID + * id_len length of ID + * idp pointer to structure to receive the ID + * + * Returns: + * 0 input was invalid + * else length of ID processed + * + */ +static int +scsp_parse_id(buff, id_len, idp) + char *buff; + int id_len; + Scsp_id *idp; +{ + /* + * Sanity check + */ + if (!buff || + id_len == 0 || id_len > SCSP_MAX_ID_LEN || + !idp) { + return(0); + } + + /* + * Save the ID length + */ + idp->id_len = id_len; + + /* + * Get the ID + */ + UM_COPY(buff, idp->id, id_len); + + /* + * Return the ID length + */ + return(id_len); +} + + +/* + * Parse the Mandatory Common Part of an SCSP input packet + * + * Arguments: + * buff pointer to mandatory common part + * pdu_len length of input packet + * mcp pointer to location of MCP in decoded record + * + * Returns: + * 0 input was invalid + * else length of MCP in message + * + */ +static int +scsp_parse_mcp(buff, pdu_len, mcp) + char *buff; + int pdu_len; + Scsp_mcp *mcp; +{ + int len; + u_char *idp, *odp; + struct scsp_nmcp *smp; + + /* + * Get the protocol ID + */ + smp = (struct scsp_nmcp *)buff; + mcp->pid = ntohs(smp->sm_pid); + if (mcp->pid < SCSP_PROTO_ATMARP || + mcp->pid > SCSP_PROTO_LNNI) { + /* Protocol ID is invalid */ + goto mcp_invalid; + } + + /* + * Get the server group ID + */ + mcp->sgid = ntohs(smp->sm_sgid); + + /* + * Get the flags + */ + mcp->flags = ntohs(smp->sm_flags); + + /* + * Get the sender ID and length + */ + idp = (u_char *) ((caddr_t)smp + sizeof(struct scsp_nmcp)); + len = scsp_parse_id(idp, smp->sm_sid_len, &mcp->sid); + if (len == 0) { + goto mcp_invalid; + } + + /* + * Get the receiver ID and length + */ + idp += len; + len = scsp_parse_id(idp, smp->sm_rid_len, &mcp->rid); + if (len == 0) { + goto mcp_invalid; + } + + /* + * Get the record count + */ + mcp->rec_cnt = ntohs(smp->sm_rec_cnt); + + /* + * Return the length of data we processed + */ + return(sizeof(struct scsp_nmcp) + smp->sm_sid_len + + smp->sm_rid_len); + +mcp_invalid: + return(0); +} + + +/* + * Parse an Extension + * + * Arguments: + * buff pointer to Extension + * pdu_len length of buffer + * expp pointer to location to receive pointer to the Extension + * + * Returns: + * 0 input was invalid + * else length of Extension processed + * + */ +static int +scsp_parse_ext(buff, pdu_len, expp) + char *buff; + int pdu_len; + Scsp_ext **expp; +{ + int len; + struct scsp_next *sep; + Scsp_ext *exp; + + /* + * Get memory for the extension + */ + sep = (struct scsp_next *)buff; + len = sizeof(Scsp_ext) + ntohs(sep->se_len); + exp = (Scsp_ext *)UM_ALLOC(len); + if (!exp) { + goto ext_invalid; + } + UM_ZERO(exp, len); + + /* + * Get the type + */ + exp->type = ntohs(sep->se_type); + + /* + * Get the length + */ + exp->len = ntohs(sep->se_len); + + /* + * Get the value + */ + if (exp->len > 0) { + UM_COPY((caddr_t)sep + sizeof(struct scsp_next), + (caddr_t)exp + sizeof(Scsp_ext), + exp->len); + } + + /* + * Save a pointer to the extension and return the + * number of bytes processed + */ + *expp = exp; + return(sizeof(struct scsp_next) + exp->len); + +ext_invalid: + if (exp) { + UM_FREE(exp); + } + return(0); +} + + +/* + * Parse a Cache State Advertisement or Cache State Advertisement + * Summary record + * + * Arguments: + * buff pointer to CSA or CSAS record + * pdu_len length of input packet + * csapp pointer to location to put pointer to CSA or CSAS + * + * Returns: + * 0 input was invalid + * else length of record processed + * + */ +static int +scsp_parse_csa(buff, pdu_len, csapp) + char *buff; + int pdu_len; + Scsp_csa **csapp; +{ + int len; + char *idp, *odp; + struct scsp_ncsa *scp; + Scsp_csa *csap; + + /* + * Check the record length + */ + scp = (struct scsp_ncsa *)buff; + if (ntohs(scp->scs_len) < (sizeof(struct scsp_ncsa) + + scp->scs_ck_len + scp->scs_oid_len)) { + goto csa_invalid; + } + + /* + * Get memory for the returned structure + */ + len = sizeof(Scsp_csa) + ntohs(scp->scs_len) - + sizeof(struct scsp_ncsa) - scp->scs_ck_len - + scp->scs_oid_len; + csap = (Scsp_csa *)UM_ALLOC(len); + if (!csap) { + goto csa_invalid; + } + UM_ZERO(csap, len); + + /* + * Get the hop count + */ + csap->hops = ntohs(scp->scs_hop_cnt); + + /* + * Set the null flag + */ + csap->null = (ntohs(scp->scs_nfill) & SCSP_CSAS_NULL) != 0; + + /* + * Get the sequence number + */ + csap->seq = get_long((u_char *)&scp->scs_seq); + + /* + * Get the cache key + */ + if (scp->scs_ck_len == 0 || + scp->scs_ck_len > SCSP_MAX_KEY_LEN) { + goto csa_invalid; + } + csap->key.key_len = scp->scs_ck_len; + idp = (char *) ((caddr_t)scp + sizeof(struct scsp_ncsa)); + UM_COPY(idp, csap->key.key, scp->scs_ck_len); + + /* + * Get the originator ID + */ + idp += scp->scs_ck_len; + len = scsp_parse_id(idp, scp->scs_oid_len, &csap->oid); + if (len == 0) { + goto csa_invalid; + } + + /* + * Get the protocol-specific data, if present + */ + len = ntohs(scp->scs_len) - (sizeof(struct scsp_ncsa) + + scp->scs_ck_len + scp->scs_oid_len); + if (len > 0) { + idp += scp->scs_oid_len; + len = scsp_parse_atmarp(idp, len, &csap->atmarp_data); + if (len == 0) + goto csa_invalid; + } + + /* + * Set a pointer to the MCP and return the length + * of data we processed + */ + *csapp = csap; + return(ntohs(scp->scs_len)); + +csa_invalid: + if (csap) + SCSP_FREE_CSA(csap); + return(0); +} + + +/* + * Parse a Cache Alignment message + * + * Arguments: + * buff pointer to start of CA in message + * pdu_len length of input packet + * capp pointer to location to put pointer to CA message + * + * Returns: + * 0 input was invalid + * else length of CA message processed + * + */ +static int +scsp_parse_ca(buff, pdu_len, capp) + char *buff; + int pdu_len; + Scsp_ca **capp; +{ + int i, len, proc_len; + struct scsp_nca *scap; + Scsp_ca *cap; + Scsp_csa **csapp; + + /* + * Get memory for the returned structure + */ + scap = (struct scsp_nca *)buff; + cap = (Scsp_ca *)UM_ALLOC(sizeof(Scsp_ca)); + if (!cap) { + goto ca_invalid; + } + UM_ZERO(cap, sizeof(Scsp_ca)); + + /* + * Get the sequence number + */ + cap->ca_seq = get_long((u_char *)&scap->sca_seq); + proc_len = sizeof(scap->sca_seq); + buff += sizeof(scap->sca_seq); + + /* + * Process the mandatory common part of the message + */ + len = scsp_parse_mcp(buff, + pdu_len - proc_len, + &cap->ca_mcp); + if (len == 0) + goto ca_invalid; + buff += len; + proc_len += len; + + /* + * Set the flags + */ + cap->ca_m = (cap->ca_mcp.flags & SCSP_CA_M) != 0; + cap->ca_i = (cap->ca_mcp.flags & SCSP_CA_I) != 0; + cap->ca_o = (cap->ca_mcp.flags & SCSP_CA_O) != 0; + + /* + * Get the CSAS records from the message + */ + for (i = 0, csapp = &cap->ca_csa_rec; i < cap->ca_mcp.rec_cnt; + i++, csapp = &(*csapp)->next) { + len = scsp_parse_csa(buff, pdu_len - proc_len, csapp); + buff += len; + proc_len += len; + } + + /* + * Set the address of the CA message and + * return the length of processed data + */ + *capp = cap; + return(proc_len); + +ca_invalid: + if (cap) + scsp_free_ca(cap); + return(0); +} + + +/* + * Parse the ATMARP-specific part of a CSA record + * + * Arguments: + * buff pointer to ATMARP part of CSU message + * pdu_len length of data to process + * acspp pointer to location to put pointer to CSU message + * + * Returns: + * 0 input was invalid + * else length of CSU Req message processed + * + */ +static int +scsp_parse_atmarp(buff, pdu_len, acspp) + char *buff; + int pdu_len; + Scsp_atmarp_csa **acspp; +{ + int i, len, proc_len; + struct scsp_atmarp_ncsa *sacp; + Scsp_atmarp_csa *acsp; + + /* + * Initial packet verification + */ + sacp = (struct scsp_atmarp_ncsa *)buff; + if ((sacp->sa_hrd != ntohs(ARP_ATMFORUM)) || + (sacp->sa_pro != ntohs(ETHERTYPE_IP))) + goto acs_invalid; + + /* + * Get memory for the returned structure + */ + acsp = (Scsp_atmarp_csa *)UM_ALLOC(sizeof(Scsp_atmarp_csa)); + if (!acsp) { + goto acs_invalid; + } + UM_ZERO(acsp, sizeof(Scsp_atmarp_csa)); + + /* + * Get state code + */ + acsp->sa_state = sacp->sa_state; + proc_len = sizeof(struct scsp_atmarp_ncsa); + + /* + * Verify/gather source ATM address + */ + acsp->sa_sha.address_format = T_ATM_ABSENT; + acsp->sa_sha.address_length = 0; + if (len = (sacp->sa_shtl & ARP_TL_LMASK)) { + if (sacp->sa_shtl & ARP_TL_E164) { + if (len > sizeof(Atm_addr_e164)) + goto acs_invalid; + acsp->sa_sha.address_format = T_ATM_E164_ADDR; + } else { + if (len != sizeof(Atm_addr_nsap)) + goto acs_invalid; + acsp->sa_sha.address_format = T_ATM_ENDSYS_ADDR; + } + acsp->sa_sha.address_length = len; + if (pdu_len < proc_len + len) + goto acs_invalid; + UM_COPY(&buff[proc_len], (char *)acsp->sa_sha.address, + len); + proc_len += len; + } + + /* + * Verify/gather source ATM subaddress + */ + acsp->sa_ssa.address_format = T_ATM_ABSENT; + acsp->sa_ssa.address_length = 0; + if (len = (sacp->sa_sstl & ARP_TL_LMASK)) { + if (((sacp->sa_sstl & ARP_TL_TMASK) != ARP_TL_NSAPA) || + (len != sizeof(Atm_addr_nsap))) + goto acs_invalid; + acsp->sa_ssa.address_format = T_ATM_ENDSYS_ADDR; + acsp->sa_ssa.address_length = len; + if (pdu_len < proc_len + len) + goto acs_invalid; + UM_COPY(&buff[proc_len], (char *)acsp->sa_ssa.address, + len); + proc_len += len; + } + + /* + * Verify/gather source IP address + */ + if (len = sacp->sa_spln) { + if (len != sizeof(struct in_addr)) + goto acs_invalid; + if (pdu_len < proc_len + len) + goto acs_invalid; + UM_COPY(&buff[proc_len], (char *)&acsp->sa_spa, len); + proc_len += len; + } else { + acsp->sa_spa.s_addr = 0; + } + + /* + * Verify/gather target ATM address + */ + acsp->sa_tha.address_format = T_ATM_ABSENT; + acsp->sa_tha.address_length = 0; + if (len = (sacp->sa_thtl & ARP_TL_LMASK)) { + if (sacp->sa_thtl & ARP_TL_E164) { + if (len > sizeof(Atm_addr_e164)) + goto acs_invalid; + acsp->sa_tha.address_format = T_ATM_E164_ADDR; + } else { + if (len != sizeof(Atm_addr_nsap)) + goto acs_invalid; + acsp->sa_tha.address_format = T_ATM_ENDSYS_ADDR; + } + acsp->sa_tha.address_length = len; + if (pdu_len < proc_len + len) + goto acs_invalid; + UM_COPY(&buff[proc_len], (char *)acsp->sa_tha.address, + len); + proc_len += len; + } + + /* + * Verify/gather target ATM subaddress + */ + acsp->sa_tsa.address_format = T_ATM_ABSENT; + acsp->sa_tsa.address_length = 0; + if (len = (sacp->sa_tstl & ARP_TL_LMASK)) { + if (((sacp->sa_tstl & ARP_TL_TMASK) != ARP_TL_NSAPA) || + (len != sizeof(Atm_addr_nsap))) + goto acs_invalid; + acsp->sa_tsa.address_format = T_ATM_ENDSYS_ADDR; + acsp->sa_tsa.address_length = len; + if (pdu_len < proc_len + len) + goto acs_invalid; + UM_COPY(&buff[proc_len], (char *)acsp->sa_tsa.address, + len); + proc_len += len; + } + + /* + * Verify/gather target IP address + */ + if (len = sacp->sa_tpln) { + if (len != sizeof(struct in_addr)) + goto acs_invalid; + if (pdu_len < proc_len + len) + goto acs_invalid; + UM_COPY(&buff[proc_len], (char *)&acsp->sa_tpa, len); + proc_len += len; + } else { + acsp->sa_tpa.s_addr = 0; + } + + /* + * Verify packet length + */ + if (proc_len != pdu_len) + goto acs_invalid; + + *acspp = acsp; + return(proc_len); + +acs_invalid: + if (acsp) + UM_FREE(acsp); + return(0); +} + + +/* + * Parse a Cache State Update Request, Cache State Update Reply, or + * Cache State Update Solicit message. These all have the same format, + * a Mandatory Common Part followed by a number of CSA or CSAS records. + * + * Arguments: + * buff pointer to start of CSU message + * pdu_len length of input packet + * csupp pointer to location to put pointer to CSU message + * + * Returns: + * 0 input was invalid + * else length of CSU Req message processed + * + */ +static int +scsp_parse_csu(buff, pdu_len, csupp) + char *buff; + int pdu_len; + Scsp_csu_msg **csupp; +{ + int i, len, proc_len; + Scsp_csu_msg *csup; + Scsp_csa **csapp; + + /* + * Get memory for the returned structure + */ + csup = (Scsp_csu_msg *)UM_ALLOC(sizeof(Scsp_csu_msg)); + if (!csup) { + goto csu_invalid; + } + UM_ZERO(csup, sizeof(Scsp_csu_msg)); + + /* + * Process the mandatory common part of the message + */ + len = scsp_parse_mcp(buff, pdu_len, &csup->csu_mcp); + if (len == 0) + goto csu_invalid; + buff += len; + proc_len = len; + + /* + * Get the CSAS records from the message + */ + for (i = 0, csapp = &csup->csu_csa_rec; + i < csup->csu_mcp.rec_cnt; + i++, csapp = &(*csapp)->next) { + len = scsp_parse_csa(buff, pdu_len - proc_len, csapp); + buff += len; + proc_len += len; + } + + /* + * Set the address of the CSU Req message and + * return the length of processed data + */ + *csupp = csup; + return(proc_len); + +csu_invalid: + if (csup) + scsp_free_csu(csup); + return(0); +} + + +/* + * Parse a Hello message + * + * Arguments: + * buff pointer to start of Hello in message + * pdu_len length of input packet + * hpp pointer to location to put pointer to Hello message + * + * Returns: + * 0 input was invalid + * else length of Hello message processed + * + */ +static int +scsp_parse_hello(buff, pdu_len, hpp) + char *buff; + int pdu_len; + Scsp_hello **hpp; +{ + int i, len, proc_len; + struct scsp_nhello *shp = (struct scsp_nhello *)buff; + Scsp_hello *hp; + Scsp_id *idp; + Scsp_id **ridpp; + + /* + * Get memory for the returned structure + */ + hp = (Scsp_hello *)UM_ALLOC(sizeof(Scsp_hello)); + if (!hp) { + goto hello_invalid; + } + UM_ZERO(hp, sizeof(Scsp_hello)); + + /* + * Get the hello interval + */ + hp->hello_int = ntohs(shp->sch_hi); + + /* + * Get the dead factor + */ + hp->dead_factor = ntohs(shp->sch_df); + + /* + * Get the family ID + */ + hp->family_id = ntohs(shp->sch_fid); + + /* + * Process the mandatory common part of the message + */ + proc_len = sizeof(struct scsp_nhello) - + sizeof(struct scsp_nmcp); + buff += proc_len; + len = scsp_parse_mcp(buff, pdu_len - proc_len, + &hp->hello_mcp); + if (len == 0) + goto hello_invalid; + buff += len; + proc_len += len; + + /* + * Get additional receiver ID records from the message + */ + for (i = 0, ridpp = &hp->hello_mcp.rid.next; + i < hp->hello_mcp.rec_cnt; + i++, ridpp = &idp->next) { + idp = (Scsp_id *)UM_ALLOC(sizeof(Scsp_id)); + if (!idp) { + goto hello_invalid; + } + UM_ZERO(idp, sizeof(Scsp_id)); + len = scsp_parse_id(buff, + hp->hello_mcp.rid.id_len, + idp); + if (len == 0) { + UM_FREE(idp); + goto hello_invalid; + } + buff += len; + proc_len += len; + *ridpp = idp; + } + + /* + * Set the address of the CA message and + * return the length of processed data + */ + *hpp = hp; + return(proc_len); + +hello_invalid: + if (hp) + scsp_free_hello(hp); + return(0); +} + + +/* + * Parse an SCSP input packet + * + * Arguments: + * buff pointer to input packet + * pdu_len length of input packet + * + * Returns: + * NULL input packet was invalid + * else pointer to packet in internal format + * + */ +Scsp_msg * +scsp_parse_msg(buff, pdu_len) + char *buff; + int pdu_len; +{ + int ext_off, len, plen; + struct scsp_nhdr *shp; + Scsp_msg *msg = (Scsp_msg *)0; + Scsp_ext **expp; + + /* + * Check the message checksum + */ + if (ip_checksum(buff, pdu_len) != 0) { + /* + * Checksum was bad--discard the message + */ + goto ignore; + } + + /* + * Allocate storage for the message + */ + msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg)); + if (!msg) { + goto ignore; + } + UM_ZERO(msg, sizeof(Scsp_msg)); + + /* + * Decode the fixed header + * + * Check the version + */ + shp = (struct scsp_nhdr *)buff; + if (shp->sh_ver != SCSP_VER_1) + goto ignore; + + /* + * Get the message type + */ + msg->sc_msg_type = shp->sh_type; + + /* + * Get and check the length + */ + len = ntohs(shp->sh_len); + if (len != pdu_len) + goto ignore; + + /* + * Get the extension offset + */ + ext_off = ntohs(shp->sh_ext_off); + + /* + * Decode the body of the message, depending on the type + */ + buff += sizeof(struct scsp_nhdr); + len -= sizeof(struct scsp_nhdr); + switch(msg->sc_msg_type) { + case SCSP_CA_MSG: + plen = scsp_parse_ca(buff, len, &msg->sc_ca); + break; + case SCSP_CSU_REQ_MSG: + case SCSP_CSU_REPLY_MSG: + case SCSP_CSUS_MSG: + plen = scsp_parse_csu(buff, len, &msg->sc_csu_msg); + break; + case SCSP_HELLO_MSG: + plen = scsp_parse_hello(buff, len, &msg->sc_hello); + break; + default: + goto ignore; + } + if (plen == 0) { + goto ignore; + } + buff += plen; + len -= plen; + + /* + * Decode any extensions + */ + if (ext_off != 0) { + for (expp = &msg->sc_ext; len > 0; + expp = &(*expp)->next) { + plen = scsp_parse_ext(buff, len, expp); + if (plen == 0) { + goto ignore; + } + buff += plen; + len -= plen; + } + } + + /* + * Make sure we handled the whole message + */ + if (len != 0) { + goto ignore; + } + + /* + * Return the address of the SCSP message in internal format + */ + return(msg); + +ignore: + if (msg) + scsp_free_msg(msg); + return(Scsp_msg *)0; +} diff --git a/usr.sbin/atm/scspd/scsp_log.c b/usr.sbin/atm/scspd/scsp_log.c new file mode 100644 index 0000000..9088078 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_log.c @@ -0,0 +1,265 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: scsp_log.c,v 1.2 1998/07/12 20:49:36 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP logging routines + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_log.c,v 1.2 1998/07/12 20:49:36 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" + +#if __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + + +/* + * Global variables + */ +FILE *scsp_trace_file = (FILE *)0; + + +/* + * Write a message to SCSP's log + * + * Arguments: + * level pointer to an SCSP cache key structure + * fmt printf-style format string + * ... parameters for printf-style use according to fmt + * + * Returns: + * none + * + */ +void +#if __STDC__ +scsp_log(const int level, const char *fmt, ...) +#else +scsp_log(level, fmt, va_alist) + int level; + char *fmt; + va_dcl +#endif +{ + va_list ap; + +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + + /* + * In debug mode, just write to stdout + */ + if (scsp_debug_mode) { + vprintf(fmt, ap); + printf("\n"); + return; + } + + /* + * Write to syslog if it's active or if no log file is set up + */ + if (scsp_log_syslog || !scsp_log_file) { + vsyslog(level, fmt, ap); + } + + /* + * Write to the log file if there's one set up + */ + if (scsp_log_file) { + vfprintf(scsp_log_file, fmt, ap); + fprintf(scsp_log_file, "\n"); + } + + va_end(ap); +} + + +/* + * Open SCSP's trace file + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +scsp_open_trace() +{ + char fname[64]; + + /* + * Build a file name + */ + UM_ZERO(fname, sizeof(fname)); + sprintf(fname, "/tmp/scspd.%d.trace", getpid()); + + /* + * Open the trace file. If the open fails, log an error, but + * keep going. The trace routine will notice that the file + * isn't open and won't try to write to it. + */ + scsp_trace_file = fopen(fname, "w"); + if (scsp_trace_file == (FILE *)0) { + scsp_log(LOG_ERR, "Can't open trace file"); + } +} + + +/* + * Write a message to SCSP's trace file + * + * Arguments: + * fmt printf-style format string + * ... parameters for printf-style use according to fmt + * + * Returns: + * none + * + */ +void +#if __STDC__ +scsp_trace(const char *fmt, ...) +#else +scsp_trace(fmt, va_alist) + char *fmt; + va_dcl +#endif +{ + va_list ap; + +#if __STDC__ + va_start(ap, fmt); +#else + va_start(ap); +#endif + + /* + * Write the message to the trace file, if it's open + */ + if (scsp_trace_file) { + vfprintf(scsp_trace_file, fmt, ap); + } + + va_end(ap); +} + + +/* + * Write an SCSP message to SCSP's trace file + * + * Arguments: + * dcsp pointer to DCS block for the message + * msg pointer to the message + * dir a direction indicator--0 for sending, 1 for receiving + * + * Returns: + * none + * + */ +void +scsp_trace_msg(dcsp, msg, dir) + Scsp_dcs *dcsp; + Scsp_msg *msg; + int dir; +{ + struct in_addr addr; + + /* + * Copy the remote IP address into a struct in_addr + */ + UM_COPY(dcsp->sd_dcsid.id, &addr.s_addr, + sizeof(struct in_addr)); + + /* + * Write the message to the trace file, if it's open + */ + if (scsp_trace_file) { + scsp_trace("SCSP message at 0x%x %s %s\n", + (u_long)msg, + (dir ? "received from" : "sent to"), + format_ip_addr(&addr)); + print_scsp_msg(scsp_trace_file, msg); + } +} + + +/* + * Log a memory error and exit + * + * Arguments: + * cp message to log + * + * Returns: + * exits, does not return + * + */ +void +scsp_mem_err(cp) + char *cp; +{ + scsp_log(LOG_CRIT, "out of memory: %s", cp); + exit(2); +} diff --git a/usr.sbin/atm/scspd/scsp_msg.c b/usr.sbin/atm/scspd/scsp_msg.c new file mode 100644 index 0000000..bed2918 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_msg.c @@ -0,0 +1,611 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: scsp_msg.c,v 1.6 1998/08/21 18:08:24 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP message-handling routines + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_msg.c,v 1.6 1998/08/21 18:08:24 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" + +/* + * Copy CSAS records into a CA record + * + * Arguments: + * dcsp pointer to DCS block for DCS + * cap pointer to CA record for CSASs + * + * + * Returns: + * none + * + */ +static void +scsp_ca_csas_setup(dcsp, cap) + Scsp_dcs *dcsp; + Scsp_ca *cap; +{ + int csas_len, len, mtu; + Scsp_server *ssp = dcsp->sd_server; + Scsp_cse *csep, *next_csep; + Scsp_csa *csap; + + /* + * Loop through pending CSAS records + */ + len = sizeof(struct scsp_nhdr) + sizeof(struct scsp_nmcp) + + ssp->ss_lsid.id_len + + dcsp->sd_dcsid.id_len; + csas_len = sizeof(struct scsp_ncsa) + + dcsp->sd_server->ss_id_len + + dcsp->sd_server->ss_ckey_len; + mtu = dcsp->sd_server->ss_mtu; + for (csep = dcsp->sd_ca_csas; + csep && (len < mtu - csas_len); + csep = next_csep) { + next_csep = csep->sc_next; + csap = scsp_cse2csas(csep); + LINK2TAIL(csap, Scsp_csa, cap->ca_csa_rec, next); + len += csas_len; + UNLINK(csep, Scsp_cse, dcsp->sd_ca_csas, sc_next); + UM_FREE(csep); + cap->ca_mcp.rec_cnt++; + } +} + + +/* + * Process CSA records from a CSU Request that may be in response to + * CSAS records sent in a CSUS + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to received message + * + * Returns: + * none + * + */ +void +scsp_csus_ack(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + Scsp_csu_msg *csusp; + Scsp_csa *csap, *csasp, *next_csasp; + + /* + * If this isn't a CSU Request, or there's no outstanding CSUS, + * or the outstanding CSUS has already been satisfied, just + * return + */ + if (!msg || msg->sc_msg_type != SCSP_CSU_REQ_MSG || + !dcsp->sd_csus_rexmt_msg || + !dcsp->sd_csus_rexmt_msg->sc_csu_msg || + !dcsp->sd_csus_rexmt_msg->sc_csu_msg->csu_csa_rec) + return; + + + /* + * Loop through the CSASs in the CSUS message, checking for + * each in the CSA records of the received CSU Request + */ + csusp = dcsp->sd_csus_rexmt_msg->sc_csu_msg; + for (csasp = csusp->csu_csa_rec; csasp; csasp = next_csasp) { + next_csasp = csasp->next; + for (csap = msg->sc_csu_msg->csu_csa_rec; + csap; csap = csap->next) { + /* + * If the records match, unlink and free the + * CSAS from the CSUS + */ + if (scsp_cmp_key(&csap->key, &csasp->key) == 0 && + scsp_cmp_key(&csap->key, &csasp->key) == 0 && + scsp_cmp_id(&csap->oid, &csasp->oid) == 0 && + csap->seq >= csasp->seq) { + UNLINK(csasp, Scsp_csa, + csusp->csu_csa_rec, + next); + SCSP_FREE_CSA(csasp); + dcsp->sd_csus_rexmt_msg->sc_csu_msg->csu_mcp.rec_cnt--; + break; + } + } + } + + if (csusp->csu_csa_rec == (Scsp_csa *)0) { + /* + * All CSASs in the CSUS message have been + * answered. Stop the timer and free the + * saved message. + */ + HARP_CANCEL(&dcsp->sd_csus_rexmt_t); + scsp_free_msg(dcsp->sd_csus_rexmt_msg); + dcsp->sd_csus_rexmt_msg = (Scsp_msg *)0; + + /* + * If the CRL isn't empty, send another CSUS + */ + if (dcsp->sd_crl) { + (void)scsp_send_csus(dcsp); + } + } +} + + +/* + * Send a CA message + * + * Arguments: + * dcsp pointer to DCS block for DCS + * + * Returns: + * 0 message sent OK + * else errno indicating reason for failure + * + */ +int +scsp_send_ca(dcsp) + Scsp_dcs *dcsp; +{ + int rc; + Scsp_msg *ca_msg; + Scsp_ca *cap; + Scsp_server *ssp = dcsp->sd_server; + + /* + * Get memory for a CA message + */ + ca_msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg)); + if (!ca_msg) { + scsp_mem_err("scsp_send_ca: sizeof(Scsp_msg)"); + } + cap = (Scsp_ca *)UM_ALLOC(sizeof(Scsp_ca)); + if (!cap) { + scsp_mem_err("scsp_send_ca: sizeof(Scsp_ca)"); + } + UM_ZERO(ca_msg, sizeof(Scsp_msg)); + UM_ZERO(cap, sizeof(Scsp_ca)); + + /* + * Fill out constant fields + */ + ca_msg->sc_msg_type = SCSP_CA_MSG; + ca_msg->sc_ca = cap; + cap->ca_seq = dcsp->sd_ca_seq; + cap->ca_mcp.pid = ssp->ss_pid; + cap->ca_mcp.sgid = ssp->ss_sgid; + cap->ca_mcp.sid = ssp->ss_lsid; + cap->ca_mcp.rid = dcsp->sd_dcsid; + + /* + * Fill out state-dependent fields + */ + switch(dcsp->sd_ca_state) { + case SCSP_CAFSM_NEG: + cap->ca_m = 1; + cap->ca_i = 1; + cap->ca_o = 1; + break; + case SCSP_CAFSM_MASTER: + cap->ca_m = 1; + cap->ca_i = 0; + scsp_ca_csas_setup(dcsp, cap); + cap->ca_o = dcsp->sd_ca_csas != (Scsp_cse *)0; + break; + case SCSP_CAFSM_SLAVE: + cap->ca_m = 0; + cap->ca_i = 0; + scsp_ca_csas_setup(dcsp, cap); + cap->ca_o = dcsp->sd_ca_csas != (Scsp_cse *)0; + break; + default: + scsp_log(LOG_ERR, "Invalid state in scsp_send_ca"); + abort(); + } + + /* + * Send the CA message and save a pointer to it in case + * it needs to be retransmitted + */ + rc = scsp_send_msg(dcsp, ca_msg); + if (rc == 0) { + dcsp->sd_ca_rexmt_msg = ca_msg; + } else { + scsp_free_msg(ca_msg); + } + + return(rc); +} + + +/* + * Send a CSU Solicit message + * + * Arguments: + * dcsp pointer to DCS block for DCS + * + * Returns: + * 0 message sent OK + * else errno indicating reason for failure + * + */ +int +scsp_send_csus(dcsp) + Scsp_dcs *dcsp; +{ + int csas_len, len, mtu, rc; + Scsp_msg *csus_msg; + Scsp_csu_msg *csusp; + Scsp_csa *csasp, *next_csasp; + Scsp_server *ssp = dcsp->sd_server; + + /* + * If we have a mesage saved for retransmission, use it. + * If not, get memory for a new one. + */ + if (dcsp->sd_csus_rexmt_msg) { + csus_msg = dcsp->sd_csus_rexmt_msg; + csusp = csus_msg->sc_csu_msg; + } else { + /* + * Get memory for a CSUS message + */ + csus_msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg)); + if (!csus_msg) { + scsp_mem_err("scsp_send_csus: sizeof(Scsp_msg)"); + } + csusp = (Scsp_csu_msg *)UM_ALLOC(sizeof(Scsp_csu_msg)); + if (!csusp) { + scsp_mem_err("scsp_send_csus: sizeof(Scsp_csu_msg)"); + } + UM_ZERO(csus_msg, sizeof(Scsp_msg)); + UM_ZERO(csusp, sizeof(Scsp_csu_msg)); + + /* + * Fill out constant fields + */ + csus_msg->sc_msg_type = SCSP_CSUS_MSG; + csus_msg->sc_csu_msg = csusp; + csusp->csu_mcp.pid = ssp->ss_pid; + csusp->csu_mcp.sgid = ssp->ss_sgid; + csusp->csu_mcp.sid = ssp->ss_lsid; + csusp->csu_mcp.rid = dcsp->sd_dcsid; + } + + /* + * Move CSAS records from CRL into message + */ + mtu = dcsp->sd_server->ss_mtu; + csas_len = sizeof(struct scsp_ncsa) + ssp->ss_id_len + + ssp->ss_ckey_len; + len = sizeof(struct scsp_nhdr) + sizeof(struct scsp_nmcp) + + 2 * ssp->ss_id_len + + csas_len * (csusp->csu_mcp.rec_cnt + 1); + for (csasp = dcsp->sd_crl; + csasp && ((len + csas_len) < mtu); + csasp = next_csasp, len += csas_len) { + next_csasp = csasp->next; + csusp->csu_mcp.rec_cnt++; + UNLINK(csasp, Scsp_csa, dcsp->sd_crl, next); + LINK2TAIL(csasp, Scsp_csa, csusp->csu_csa_rec, next); + csasp->hops = 1; + } + + /* + * Send the CSUS message and save a pointer to it in case + * it needs to be retransmitted + */ + rc = scsp_send_msg(dcsp, csus_msg); + if (rc == 0) { + /* + * Success--Save a pointer to the message and + * start the CSUS retransmit timer + */ + dcsp->sd_csus_rexmt_msg = csus_msg; + HARP_TIMER(&dcsp->sd_csus_rexmt_t, + dcsp->sd_csus_rexmt_int, + scsp_csus_retran_timeout); + } else { + /* + * Error--free the CSUS message + */ + scsp_free_msg(csus_msg); + } + + return(rc); +} + + +/* + * Send a CSU Request message + * + * Arguments: + * dcsp pointer to DCS block for DCS + * csap pointer to CSAs to include + * + * Returns: + * 0 message sent OK + * else errno indicating reason for failure + * + */ +int +scsp_send_csu_req(dcsp, csap) + Scsp_dcs *dcsp; + Scsp_csa *csap; +{ + int rc; + Scsp_server *ssp = dcsp->sd_server; + Scsp_csa *cnt_csap; + Scsp_msg *csu_msg; + Scsp_csu_msg *csup; + Scsp_csu_rexmt *rxp; + + /* + * Return if CSA list is empty + */ + if (!csap) + return(0); + + /* + * Get memory for a CSU Req message + */ + csu_msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg)); + if (!csu_msg) { + scsp_mem_err("scsp_send_csu_req: sizeof(Scsp_msg)"); + } + csup = (Scsp_csu_msg *)UM_ALLOC(sizeof(Scsp_csu_msg)); + if (!csup) { + scsp_mem_err("scsp_send_csu_req: sizeof(Scsp_csu_msg)"); + } + UM_ZERO(csu_msg, sizeof(Scsp_msg)); + UM_ZERO(csup, sizeof(Scsp_csu_msg)); + + /* + * Get memory for a CSU Req retransmission queue entry + */ + rxp = (Scsp_csu_rexmt *)UM_ALLOC(sizeof(Scsp_csu_rexmt)); + if (!rxp) { + scsp_mem_err("scsp_send_csu_req: sizeof(Scsp_csu_rexmt)"); + } + UM_ZERO(rxp, sizeof(Scsp_csu_rexmt)); + + /* + * Fill out constant fields + */ + csu_msg->sc_msg_type = SCSP_CSU_REQ_MSG; + csu_msg->sc_csu_msg = csup; + csup->csu_mcp.pid = ssp->ss_pid; + csup->csu_mcp.sgid = ssp->ss_sgid; + csup->csu_mcp.sid = ssp->ss_lsid; + csup->csu_mcp.rid = dcsp->sd_dcsid; + + /* + * Put the CSA list into the message + */ + csup->csu_csa_rec = csap; + for (cnt_csap = csap; cnt_csap; cnt_csap = cnt_csap->next) { + csup->csu_mcp.rec_cnt++; + } + + /* + * Send the CSU Request + */ + rc = scsp_send_msg(dcsp, csu_msg); + if (rc) { + scsp_free_msg(csu_msg); + return(rc); + } + UM_FREE(csu_msg); + UM_FREE(csup); + + /* + * Save the CSA entries on the CSU Request retransmission + * queue and start the retransmission timer + */ + rxp->sr_dcs = dcsp; + rxp->sr_csa = csap; + HARP_TIMER(&rxp->sr_t, dcsp->sd_csu_rexmt_int, + scsp_csu_req_retran_timeout); + LINK2TAIL(rxp, Scsp_csu_rexmt, dcsp->sd_csu_rexmt, sr_next); + + return(0); +} + + +/* + * Send a CSU Reply message + * + * Arguments: + * dcsp pointer to DCS block for DCS + * csap pointer to CSAs to include + * + * Returns: + * 0 message sent OK + * errno reason for failure + * + */ +int +scsp_send_csu_reply(dcsp, csap) + Scsp_dcs *dcsp; + Scsp_csa *csap; +{ + int rc; + Scsp_server *ssp = dcsp->sd_server; + Scsp_csa *csap1; + Scsp_msg *csu_msg; + Scsp_csu_msg *csup; + + /* + * Return if CSA list is empty + */ + if (!csap) + return(0); + + /* + * Get memory for a CSU Reply message + */ + csu_msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg)); + if (!csu_msg) { + scsp_mem_err("scsp_send_csu_reply: sizeof(Scsp_msg)"); + } + csup = (Scsp_csu_msg *)UM_ALLOC(sizeof(Scsp_csu_msg)); + if (!csup) { + scsp_mem_err("scsp_send_csu_reply: sizeof(Scsp_csu_msg)"); + } + UM_ZERO(csu_msg, sizeof(Scsp_msg)); + UM_ZERO(csup, sizeof(Scsp_csu_msg)); + + /* + * Fill out constant fields + */ + csu_msg->sc_msg_type = SCSP_CSU_REPLY_MSG; + csu_msg->sc_csu_msg = csup; + csup->csu_mcp.pid = ssp->ss_pid; + csup->csu_mcp.sgid = ssp->ss_sgid; + csup->csu_mcp.sid = ssp->ss_lsid; + csup->csu_mcp.rid = dcsp->sd_dcsid; + + /* + * Put the CSA list into the message. Convert the CSAs into + * CSASs by freeing the protocol-specific portion. + */ + csup->csu_csa_rec = csap; + for (csap1 = csap; csap1; csap1 = csap1->next) { + switch(dcsp->sd_server->ss_pid) { + /* + * We currently only support ATMARP + */ + case SCSP_PROTO_ATMARP: + if (csap1->atmarp_data) { + UM_FREE(csap1->atmarp_data); + csap1->atmarp_data = + (Scsp_atmarp_csa *)0; + } + break; + } + csup->csu_mcp.rec_cnt++; + } + + /* + * Send the CSU Reply + */ + rc = scsp_send_msg(dcsp, csu_msg); + scsp_free_msg(csu_msg); + + return(rc); +} + + +/* + * Send a Hello message + * + * Arguments: + * dcsp pointer to DCS control block + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_send_hello(dcsp) + Scsp_dcs *dcsp; +{ + int rc; + Scsp_msg *hello; + Scsp_hello *hp; + + /* + * Get memory for a Hello message + */ + hello = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg)); + if (!hello) { + scsp_mem_err("scsp_send_hello: sizeof(Scsp_msg)"); + } + UM_ZERO(hello, sizeof(Scsp_msg)); + hp = (Scsp_hello *)UM_ALLOC(sizeof(Scsp_hello)); + if (!hp) { + scsp_mem_err("scsp_send_hello: sizeof(Scsp_hello)"); + } + UM_ZERO(hp, sizeof(Scsp_hello)); + + /* + * Set up the Hello message + */ + hello->sc_msg_type = SCSP_HELLO_MSG; + hello->sc_hello = hp; + hp->hello_int = SCSP_HELLO_Interval; + hp->dead_factor = SCSP_HELLO_DF; + hp->family_id = dcsp->sd_server->ss_fid; + hp->hello_mcp.pid = dcsp->sd_server->ss_pid; + hp->hello_mcp.sgid = dcsp->sd_server->ss_sgid; + hp->hello_mcp.flags = 0; + hp->hello_mcp.rec_cnt = 0; + hp->hello_mcp.sid = dcsp->sd_server->ss_lsid; + hp->hello_mcp.rid = dcsp->sd_dcsid; + + /* + * Send and free the message + */ + rc = scsp_send_msg(dcsp, hello); + scsp_free_msg(hello); + + return(rc); +} diff --git a/usr.sbin/atm/scspd/scsp_msg.h b/usr.sbin/atm/scspd/scsp_msg.h new file mode 100644 index 0000000..3ee3bf5 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_msg.h @@ -0,0 +1,462 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: scsp_msg.h,v 1.1 1998/07/10 15:29:02 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP message formats + * + */ + +#ifndef _SCSP_SCSP_MSG_H +#define _SCSP_SCSP_MSG_H + + +/* + * ATMARP constants + */ +#define ARP_ATMFORUM 19 +#define ARP_TL_TMASK 0x40 /* Type mask */ +#define ARP_TL_NSAPA 0x00 /* Type = ATM Forum NSAPA */ +#define ARP_TL_E164 0x40 /* Type = E.164 */ +#define ARP_TL_LMASK 0x3f /* Length mask */ + + +/* + * SCSP version number + */ +#define SCSP_VER_1 1 + + +/* + * SCSP message types + */ +#define SCSP_CA_MSG 1 +#define SCSP_CSU_REQ_MSG 2 +#define SCSP_CSU_REPLY_MSG 3 +#define SCSP_CSUS_MSG 4 +#define SCSP_HELLO_MSG 5 + + +/* + * SCSP Client Protocol IDs + */ +#define SCSP_PROTO_ATMARP 1 +#define SCSP_PROTO_NHRP 2 +#define SCSP_PROTO_MARS 3 +#define SCSP_PROTO_DHCP 4 +#define SCSP_PROTO_LNNI 5 + + +/* + * Extension types + */ +#define SCSP_EXT_END 0 +#define SCSP_EXT_AUTH 1 +#define SCSP_EXT_VENDOR 2 + +/* + * Sequence number bounds + */ +#define SCSP_CSA_SEQ_MIN 0x80000001 +#define SCSP_CSA_SEQ_MAX 0x7FFFFFFF + + +/* + * Sender, Receiver, or Originator ID lengths + */ +#define SCSP_ATMARP_ID_LEN 4 +#define SCSP_NHRP_ID_LEN 4 +#define SCSP_MAX_ID_LEN 4 + + +/* + * Cache Key lengths + */ +#define SCSP_ATMARP_KEY_LEN 4 +#define SCSP_NHRP_KEY_LEN 4 +#define SCSP_MAX_KEY_LEN 4 + + +/* + * Fixed header + */ +struct scsp_nhdr { + u_char sh_ver; /* SCSP version */ + u_char sh_type; /* Message type */ + u_short sh_len; /* Message length */ + u_short sh_checksum; /* IP checksum over message */ + u_short sh_ext_off; /* Offset of first extension */ +}; + + +/* + * Mandatory common part + */ +struct scsp_nmcp { + u_short sm_pid; /* Protocol ID */ + u_short sm_sgid; /* Server group ID */ + u_short sm_fill_0; /* Unused */ + u_short sm_flags; /* Flags--see below */ + u_char sm_sid_len; /* Sender ID length */ + u_char sm_rid_len; /* Receiver ID length */ + u_short sm_rec_cnt; /* Number of records */ +#ifdef NOTDEF + /* Variable length fields */ + u_char sm_sid[]; /* Sender ID (variable) */ + u_char sm_rid[]; /* Receiver ID (variable) */ +#endif +}; + + +/* + * Extensions part + */ +struct scsp_next { + u_short se_type; /* Extension type */ + u_short se_len; /* Length */ +#ifdef NOTDEF + /* Variable length fields */ + u_char se_value[]; /* Extension value */ +#endif +}; + + +/* + * Cache State Advertisement record or + * Cache State Advertisement Summary record + */ +struct scsp_ncsa { + u_short scs_hop_cnt; /* Hop count */ + u_short scs_len; /* Record length */ + u_char scs_ck_len; /* Cache key length */ + u_char scs_oid_len; /* Originator ID length */ + u_short scs_nfill; /* Null bit and filler */ + long scs_seq; /* Sequence number */ +#ifdef NOTDEF + /* Variable length fields */ + u_char scs_ckey[]; /* Cache key */ + u_char scs_oid[]; /* Originator ID */ + u_char scs_proto[]; /* Protocol-specific (in CSA) */ +#endif +}; + +#define SCSP_CSAS_NULL 0x8000 + + +/* + * Cache Alignment message + */ +struct scsp_nca { + long sca_seq; /* Sequence number */ + struct scsp_nmcp sca_mcp; /* Mandatory common */ +#ifdef NOTDEF + /* Variable length fields */ + struct scsp_ncsa sca_rec[]; /* CSASs */ +#endif +}; + +#define SCSP_CA_M 0x8000 /* Master/Slave bit */ +#define SCSP_CA_I 0x4000 /* Initialization bit */ +#define SCSP_CA_O 0x2000 /* More bit */ + + +/* + * Cache State Update Request, Cache State Update Reply, or + * Cache State Update Solicit message + */ +struct scsp_ncsu_msg { + struct scsp_nmcp scr_mcp; /* Mandatory common */ +#ifdef NOTDEF + /* Variable length fields */ + struct scsp_ncsa scr_rec[]; /* CSAs */ +#endif +}; + + +/* + * Hello message + */ +struct scsp_nhello { + u_short sch_hi; /* Hello interval */ + u_short sch_df; /* Dead factor */ + u_short sch_fill_0; /* Unused */ + u_short sch_fid; /* Family ID */ + struct scsp_nmcp sch_mcp; /* Mandatory common */ +#ifdef NOTDEF + /* Variable-length fields */ + struct scsp_nrid sch_rid[]; /* Receiver IDs */ +#endif +}; + + +/* + * ATMARP-specific Cache State Advertisement record + */ +struct scsp_atmarp_ncsa { + u_short sa_hrd; /* Hardware type -- 0x0013 */ + u_short sa_pro; /* Protocol type -- 0x0800 */ + u_char sa_shtl; /* Src ATM addr type/len */ + u_char sa_sstl; /* Src ATM subaddr type/len */ + u_char sa_state; /* State */ + u_char sa_fill1; /* Unused */ + u_char sa_spln; /* Src proto addr type */ + u_char sa_thtl; /* Tgt ATM addr type/len */ + u_char sa_tstl; /* Tgt ATM subaddr type/len */ + u_char sa_tpln; /* Tgt proto addr len */ +#ifdef NOTDEF + /* Variable-length fields */ + u_char sa_sha[]; /* Source ATM addr */ + u_char sa_ssa[]; /* Source ATM subaddr */ + u_char sa_spa[]; /* Source IP addr */ + u_char sa_tha[]; /* Target ATM addr */ + u_char sa_tsa[]; /* Target ATM subaddr */ + u_char sa_tpa[]; /* Target IP addr */ +#endif +}; + + +/* + * NHRP-specific Cache State Advertisement record + */ +struct scsp_nhrp_ncsa { + u_short sn_af; /* Address family */ + u_short sn_pro; /* NHRP protocol type */ + u_char sn_snap[5]; /* SNAP header */ + u_char sn_ver; /* NHRP version no. */ + u_short sn_flags; /* Flags */ + u_long sn_rid; /* Request ID */ + u_char sn_state; /* State */ + u_char sn_pln; /* Prefix length */ + u_short sn_fill1; /* Unused */ + u_short sn_mtu; /* MTU */ + u_short sn_hold; /* Holding time */ + u_char sn_csatl; /* Client addr type/len */ + u_char sn_csstl; /* Client subaddr type/len */ + u_char sn_cpln; /* Client proto addr len */ + u_char sn_pref; /* Preference for next hop */ +#ifdef NOTDEF + /* Variable-length fields */ + u_char sn_csa[]; /* Client subnetwork addr */ + u_char sn_css[]; /* Client subnetwork subaddr */ + u_char sn_cpa[]; /* Client protocol addr */ +#endif +}; + + +/* + * SCSP messages in internal format + * + * + * Fixed message header + */ +struct scsp_hdr { + u_char msg_type; /* Message type */ +}; +typedef struct scsp_hdr Scsp_hdr; + + +/* + * Sender or Receiver ID structure + */ +struct scsp_id { + struct scsp_id *next; /* Next ID */ + u_char id_len; /* ID length */ + u_char id[SCSP_MAX_ID_LEN]; /* ID */ +}; +typedef struct scsp_id Scsp_id; + + +/* + * Cacke Key structure + */ +struct scsp_ckey { + u_char key_len; /* Cache key length */ + u_char key[SCSP_MAX_KEY_LEN]; /* Cache key */ +}; +typedef struct scsp_ckey Scsp_ckey; + + +/* + * Mandatory common part + */ +struct scsp_mcp { + u_short pid; /* Protocol ID */ + u_short sgid; /* Server group ID */ + u_short flags; /* Flags */ + u_short rec_cnt; /* No. of records attached */ + Scsp_id sid; /* Sender ID */ + Scsp_id rid; /* Receiver ID */ +}; +typedef struct scsp_mcp Scsp_mcp; + + +/* + * Extensions part + */ +struct scsp_ext { + struct scsp_ext *next; /* Next extension */ + u_short type; /* Extension type */ + u_short len; /* Length */ +#ifdef NOTDEF + /* Variable length fields */ + u_char value[]; /* Extension value */ +#endif +}; +typedef struct scsp_ext Scsp_ext; + + +/* + * Cache State Advertisement record or + * Cache State Advertisement Summary record + */ +struct scsp_csa { + struct scsp_csa *next; /* Next CSAS record */ + u_short hops; /* Hop count */ + u_char null; /* Null flag */ + u_long seq; /* CSA seq. no. */ + Scsp_ckey key; /* Cache key */ + Scsp_id oid; /* Originator ID */ + int trans_ct; /* No. of times CSA sent */ + struct scsp_atmarp_csa *atmarp_data; /* ATMARP data */ +#ifdef NOTDEF + struct scsp_nhrp_csa *nhrp_data; /* NHRP data */ +#endif +}; +typedef struct scsp_csa Scsp_csa; + +/* + * Macro to free a CSA and any associated protocol-specific data + */ +#define SCSP_FREE_CSA(c) \ +{ \ + if ((c)->atmarp_data) { \ + UM_FREE((c)->atmarp_data); \ + } \ + UM_FREE((c)); \ +} + + +/* + * Cache Alignment message + */ +struct scsp_ca { + long ca_seq; /* CA msg sequence no. */ + u_char ca_m; /* Master/slave bit */ + u_char ca_i; /* Initialization bit */ + u_char ca_o; /* More bit */ + Scsp_mcp ca_mcp; /* Mandatory common part */ + Scsp_csa *ca_csa_rec; /* Ptr. to CSAS records */ +}; +typedef struct scsp_ca Scsp_ca; + + +/* + * Cache State Update Request, Cache State Update Reply, or + * Cache State Update Solicit message + */ +struct scsp_csu_msg { + Scsp_mcp csu_mcp; /* Mandatory common part */ + Scsp_csa *csu_csa_rec; /* Ptr. to CSA records */ +}; +typedef struct scsp_csu_msg Scsp_csu_msg; + + +/* + * Hello message + */ +struct scsp_hello { + u_short hello_int; /* Hello interval */ + u_short dead_factor; /* When is DCS dead? */ + u_short family_id; /* Family ID */ + Scsp_mcp hello_mcp; /* Mandatory common part */ +}; +typedef struct scsp_hello Scsp_hello; + + +/* + * NHRP-specific Cache State Advertisement record + */ +struct scsp_nhrp_csa { + u_char req_id; /* Request ID */ + u_char state; /* State */ + u_char pref_len; /* Prefix length */ + u_short flags; /* See below */ + u_short mtu; /* Maximim transmission unit */ + u_short hold_time; /* Entry holding time */ + u_char caddr_tlen; /* Client addr type/length */ + u_char csaddr_tlen; /* Client subaddr type/length */ + u_char cproto_len; /* Client proto addr length */ + u_char pref; /* Preference */ + Atm_addr caddr; /* Client address */ + Atm_addr csaddr; /* Client subaddress */ + struct in_addr cproto_addr; /* Client protocol address */ +}; +typedef struct scsp_nhrp Scsp_nhrp; + +#define SCSP_NHRP_UNIQ 0x8000 +#define SCSP_NHRP_ARP 0x4000 + + +/* + * ATMARP-specific Cache State Advertisement record + */ +struct scsp_atmarp_csa { + u_char sa_state; /* State */ + Atm_addr sa_sha; /* Source ATM addr */ + Atm_addr sa_ssa; /* Source ATM subaddr */ + struct in_addr sa_spa; /* Source IP addr */ + Atm_addr sa_tha; /* Target ATM addr */ + Atm_addr sa_tsa; /* Target ATM subaddr */ + struct in_addr sa_tpa; /* Target IP addr */ +}; +typedef struct scsp_atmarp_csa Scsp_atmarp_csa; + + +/* + * SCSP message + */ +struct scsp_msg { + Scsp_hdr sc_hdr; + union { + Scsp_ca *sc_u_ca; + Scsp_csu_msg *sc_u_csu_msg; + Scsp_hello *sc_u_hello; + } sc_msg_u; + Scsp_ext *sc_ext; +}; +typedef struct scsp_msg Scsp_msg; + +#define sc_msg_type sc_hdr.msg_type +#define sc_ca sc_msg_u.sc_u_ca +#define sc_csu_msg sc_msg_u.sc_u_csu_msg +#define sc_hello sc_msg_u.sc_u_hello + +#endif /* _SCSP_SCSP_MSG_H */ diff --git a/usr.sbin/atm/scspd/scsp_output.c b/usr.sbin/atm/scspd/scsp_output.c new file mode 100644 index 0000000..10ee493 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_output.c @@ -0,0 +1,934 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: scsp_output.c,v 1.2 1998/07/12 20:49:45 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * Output packet processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_output.c,v 1.2 1998/07/12 20:49:45 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netinet/if_ether.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" + + +/* + * Put a long integer into the output buffer + * + * This routine is provided for cases where long ints may not be + * word-aligned in the output buffer. + * + * Arguments: + * l long integer + * cp pointer to output buffer + * + * Returns: + * None + * + */ +static void +put_long(l, cp) + u_long l; + u_char *cp; +{ + u_long nl; + + /* + * Convert to network order and copy to output buffer + */ + nl = htonl(l); + UM_COPY(&nl, cp, sizeof(u_long)); +} + + +/* + * Format a Sender or Receiver ID + * + * Arguments: + * idp ponter to ID structure + * buff pointer to ID + * + * Returns: + * 0 input was invalid + * else length of ID processed + * + */ +static int +scsp_format_id(idp, buff) + Scsp_id *idp; + char *buff; +{ + /* + * Copy the ID + */ + UM_COPY(idp->id, buff, idp->id_len); + + /* + * Return the ID length + */ + return(idp->id_len); +} + + +/* + * Format the Mandatory Common Part of an SCSP input packet + * + * Arguments: + * mcp pointer to MCP + * buff pointer to mandatory common part + * + * Returns: + * 0 input was invalid + * else length of MCP in message + * + */ +static int +scsp_format_mcp(mcp, buff) + Scsp_mcp *mcp; + char *buff; +{ + int len; + char *idp, *odp; + struct scsp_nmcp *smp; + + /* + * Set the protocol ID + */ + smp = (struct scsp_nmcp *)buff; + smp->sm_pid = htons(mcp->pid); + + /* + * Set the server group ID + */ + smp->sm_sgid = htons(mcp->sgid); + + /* + * Set the flags + */ + smp->sm_flags = htons(mcp->flags); + + /* + * Set the sender ID and length + */ + smp->sm_sid_len = mcp->sid.id_len; + odp = buff + sizeof(struct scsp_nmcp); + len = scsp_format_id(&mcp->sid, odp); + if (len == 0) { + goto mcp_invalid; + } + + /* + * Set the receiver ID and length + */ + smp->sm_rid_len = mcp->rid.id_len; + odp += mcp->sid.id_len; + len = scsp_format_id(&mcp->rid, odp); + if (len == 0) { + goto mcp_invalid; + } + + /* + * Set the record count + */ + smp->sm_rec_cnt = htons(mcp->rec_cnt); + + /* + * Return the length of data we processed + */ + return(sizeof(struct scsp_nmcp) + mcp->sid.id_len + + mcp->rid.id_len); + +mcp_invalid: + return(0); +} + + +/* + * Format an Extension + * + * Arguments: + * exp pointer to extension in internal format + * buff pointer to output buffer + * blen space available in buffer + * + * Returns: + * 0 input was invalid + * else length of extension processed + * + */ +static int +scsp_format_ext(exp, buff, blen) + Scsp_ext *exp; + char *buff; + int blen; +{ + int len; + struct scsp_next *sep; + + /* + * Make sure there's room in the buffer + */ + if (blen < (sizeof(struct scsp_next) + exp->len)) + return(0); + + /* + * Set the type + */ + sep = (struct scsp_next *)buff; + sep->se_type = htons(exp->type); + + /* + * Set the length + */ + sep->se_len = htons(exp->len); + + /* + * Set the value + */ + if (exp->len > 0) { + buff += sizeof(struct scsp_next); + UM_COPY((caddr_t)exp + sizeof(Scsp_ext), + buff, + exp->len); + } + + /* + * Return the number of bytes processed + */ + return(sizeof(struct scsp_next) + exp->len); +} + + +/* + * Format the ATMARP part of a CSA record + * + * Arguments: + * acsp pointer to ATMARP protocol-specific CSA record + * buff pointer to output buffer + * + * Returns: + * 0 input was invalid + * else length of record processed + * + */ +static int +scsp_format_atmarp(acsp, buff) + Scsp_atmarp_csa *acsp; + char *buff; +{ + char *cp; + int len, pkt_len, rc; + struct scsp_atmarp_ncsa *sanp; + + /* + * Figure out how long PDU is going to be + */ + pkt_len = sizeof(struct scsp_atmarp_ncsa); + switch (acsp->sa_sha.address_format) { + case T_ATM_ENDSYS_ADDR: + pkt_len += acsp->sa_sha.address_length; + break; + + case T_ATM_E164_ADDR: + pkt_len += acsp->sa_sha.address_length; + if (acsp->sa_ssa.address_format == T_ATM_ENDSYS_ADDR) + pkt_len += acsp->sa_ssa.address_length; + break; + } + + switch (acsp->sa_tha.address_format) { + case T_ATM_ENDSYS_ADDR: + pkt_len += acsp->sa_tha.address_length; + break; + + case T_ATM_E164_ADDR: + pkt_len += acsp->sa_tha.address_length; + if (acsp->sa_tha.address_format == T_ATM_ENDSYS_ADDR) + pkt_len += acsp->sa_tha.address_length; + break; + } + + if (acsp->sa_spa.s_addr != 0) + pkt_len += sizeof(struct in_addr); + + if (acsp->sa_tpa.s_addr != 0) + pkt_len += sizeof(struct in_addr); + + /* + * Set up pointers + */ + sanp = (struct scsp_atmarp_ncsa *)buff; + cp = (char *)sanp + sizeof(struct scsp_atmarp_ncsa); + + /* + * Build fields + */ + sanp->sa_hrd = htons(ARP_ATMFORUM); + sanp->sa_pro = htons(ETHERTYPE_IP); + + /* sa_sha */ + len = acsp->sa_sha.address_length; + switch (acsp->sa_sha.address_format) { + case T_ATM_ENDSYS_ADDR: + sanp->sa_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* sa_sha */ + UM_COPY(acsp->sa_sha.address, cp, len); + cp += len; + + sanp->sa_sstl = 0; + break; + + case T_ATM_E164_ADDR: + sanp->sa_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK); + + /* sa_sha */ + UM_COPY(acsp->sa_sha.address, cp, len); + cp += len; + + if (acsp->sa_ssa.address_format == T_ATM_ENDSYS_ADDR) { + len = acsp->sa_ssa.address_length; + sanp->sa_sstl = ARP_TL_NSAPA | + (len & ARP_TL_LMASK); + + /* sa_ssa */ + UM_COPY(acsp->sa_ssa.address, cp, len); + cp += len; + } else + sanp->sa_sstl = 0; + break; + + default: + sanp->sa_shtl = 0; + sanp->sa_sstl = 0; + } + + /* sa_state */ + sanp->sa_state = acsp->sa_state; + sanp->sa_fill1 = 0; + + /* sa_spa */ + if (acsp->sa_spa.s_addr != 0) { + sanp->sa_spln = sizeof(struct in_addr); + UM_COPY(&acsp->sa_spa, cp, sizeof(struct in_addr)); + cp += sizeof(struct in_addr); + } + + /* sa_tha */ + len = acsp->sa_tha.address_length; + switch (acsp->sa_tha.address_format) { + case T_ATM_ENDSYS_ADDR: + sanp->sa_thtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK); + + /* sa_tha */ + UM_COPY(acsp->sa_tha.address, cp, len); + cp += len; + + sanp->sa_tstl = 0; + break; + + case T_ATM_E164_ADDR: + sanp->sa_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK); + + /* sa_tha */ + UM_COPY(acsp->sa_tha.address, cp, len); + cp += len; + + if (acsp->sa_tsa.address_format == T_ATM_ENDSYS_ADDR) { + len = acsp->sa_tha.address_length; + sanp->sa_tstl = ARP_TL_NSAPA | + (len & ARP_TL_LMASK); + + /* sa_tsa */ + UM_COPY(acsp->sa_tsa.address, cp, len); + cp += len; + } else + sanp->sa_tstl = 0; + break; + + default: + sanp->sa_thtl = 0; + sanp->sa_tstl = 0; + } + + /* sa_tpa */ + if (acsp->sa_tpa.s_addr != 0) { + sanp->sa_tpln = sizeof(struct in_addr); + UM_COPY(&acsp->sa_tpa, cp, sizeof(struct in_addr)); + } + + return(pkt_len); +} + + +/* + * Format a Cache State Advertisement or Cache State Advertisement + * Summary record + * + * Arguments: + * csapp pointer to CSA or CSAS + * buff pointer to output buffer + * + * Returns: + * 0 input was invalid + * else length of record processed + * + */ +static int +scsp_format_csa(csap, buff) + Scsp_csa *csap; + char *buff; +{ + int len = 0; + char *idp, *odp; + struct scsp_ncsa *scp; + + /* + * Set the hop count + */ + scp = (struct scsp_ncsa *)buff; + scp->scs_hop_cnt = htons(csap->hops); + + /* + * Set the null flag + */ + if (csap->null) { + scp->scs_nfill = htons(SCSP_CSAS_NULL); + } + + /* + * Set the sequence number + */ + put_long(csap->seq, (u_char *)&scp->scs_seq); + + /* + * Set the cache key + */ + scp->scs_ck_len = csap->key.key_len; + odp = buff + sizeof(struct scsp_ncsa); + UM_COPY(csap->key.key, odp, scp->scs_ck_len); + + /* + * Set the originator ID + */ + odp += scp->scs_ck_len; + scp->scs_oid_len = scsp_format_id(&csap->oid, odp); + + /* + * Set the protocol-specific data, if present. At the + * moment, we only handle data for ATMARP. + */ + if (csap->atmarp_data) { + odp += scp->scs_oid_len; + len = scsp_format_atmarp(csap->atmarp_data, odp); + } + + /* + * Set the record length + */ + scp->scs_len = htons(sizeof(struct scsp_ncsa) + + scp->scs_ck_len + scp->scs_oid_len + + len); + + /* + * Return the length of data we processed + */ + return(ntohs(scp->scs_len)); +} + + +/* + * Format a Cache Alignment message + * + * Arguments: + * cap pointer to CA message + * buff pointer to output buffer + * blen space available in buffer + * + * Returns: + * 0 input was invalid + * else length of CA message processed + * + */ +static int +scsp_format_ca(cap, buff, blen) + Scsp_ca *cap; + char *buff; + int blen; +{ + int i, len, proc_len; + struct scsp_nca *scap; + Scsp_csa *csap; + + /* + * Set the sequence number + */ + scap = (struct scsp_nca *)buff; + put_long(cap->ca_seq, (u_char *)&scap->sca_seq); + proc_len = sizeof(scap->sca_seq); + buff += sizeof(scap->sca_seq); + + /* + * Set the flags + */ + cap->ca_mcp.flags = 0; + if (cap->ca_m) + cap->ca_mcp.flags |= SCSP_CA_M; + if (cap->ca_i) + cap->ca_mcp.flags |= SCSP_CA_I; + if (cap->ca_o) + cap->ca_mcp.flags |= SCSP_CA_O; + + /* + * Format the mandatory common part of the message + */ + len = scsp_format_mcp(&cap->ca_mcp, buff); + if (len == 0) + goto ca_invalid; + buff += len; + proc_len += len; + + /* + * Put any CSAS records into the message + */ + for (i = 0, csap = cap->ca_csa_rec; i < cap->ca_mcp.rec_cnt; + i++, csap = csap->next) { + len = scsp_format_csa(csap, buff); + buff += len; + proc_len += len; + if (proc_len > blen) { + scsp_log(LOG_CRIT, "scsp_format_ca: buffer overflow"); + abort(); + } + } + + /* + * Return the length of processed data + */ + return(proc_len); + +ca_invalid: + return(0); +} + + +/* + * Format a Cache State Update Request, Cache State Update Reply, or + * Cache State Update Solicit message. These all have the same format, + * a Mandatory Common Part followed by a number of CSA or CSAS records. + * + * Arguments: + * csup pointer to location to put pointer to CSU Req message + * buff pointer to output buffer + * blen space available in buffer + * + * Returns: + * 0 input was invalid + * else length of CSU Req message processed + * + */ +static int +scsp_format_csu(csup, buff, blen) + Scsp_csu_msg *csup; + char *buff; + int blen; +{ + int i, len, proc_len; + struct scsp_ncsu_msg *scsup; + Scsp_csa *csap; + + /* + * Format the mandatory common part of the message + */ + scsup = (struct scsp_ncsu_msg *)buff; + len = scsp_format_mcp(&csup->csu_mcp, buff); + if (len == 0) + goto csu_invalid; + buff += len; + proc_len = len; + + /* + * Put the CSAS records into the message + */ + for (i = 0, csap = csup->csu_csa_rec; + i < csup->csu_mcp.rec_cnt && csap; + i++, csap = csap->next) { + len = scsp_format_csa(csap, buff); + buff += len; + proc_len += len; + if (proc_len > blen) { + scsp_log(LOG_CRIT, "scsp_format_csu: buffer overflow"); + abort(); + } + } + + /* + * Return the length of processed data + */ + return(proc_len); + +csu_invalid: + return(0); +} + + +/* + * Format a Hello message + * + * Arguments: + * hpp pointer to Hello message + * buff pointer to output buffer + * blen space available in buffer + * + * Returns: + * 0 input was invalid + * else length of Hello message processed + * + */ +static int +scsp_format_hello(hp, buff, blen) + Scsp_hello *hp; + char *buff; + int blen; +{ + int i, len, proc_len; + struct scsp_nhello *shp; + Scsp_id *idp; + Scsp_id *ridp; + + /* + * Set the hello interval + */ + shp = (struct scsp_nhello *)buff; + shp->sch_hi = htons(hp->hello_int); + + /* + * Set the dead factor + */ + shp->sch_df = htons(hp->dead_factor); + + /* + * Set the family ID + */ + shp->sch_fid = htons(hp->family_id); + + /* + * Process the mandatory common part of the message + */ + proc_len = sizeof(struct scsp_nhello) - + sizeof(struct scsp_nmcp); + buff += proc_len; + len = scsp_format_mcp(&hp->hello_mcp, buff); + if (len == 0) + goto hello_invalid; + proc_len += len; + buff += len; + + /* + * Add any additional receiver ID records to the message + */ + for (ridp = hp->hello_mcp.rid.next; ridp; + ridp = ridp->next) { + len = scsp_format_id(ridp, buff); + if (len == 0) { + goto hello_invalid; + } + proc_len += len; + buff += len; + } + + /* + * Return the length of the Hello message body + */ + if (proc_len > blen) { + scsp_log(LOG_CRIT, "scsp_format_hello: buffer overflow"); + abort(); + } + return(proc_len); + +hello_invalid: + return(0); +} + + +/* + * Format an SCSP output packet + * + * Arguments: + * dcsp pointer to DCS for which message is being prepared + * msg pointer to input packet + * bpp pointer to location to put pointer to formatted packet + * + * Returns: + * 0 input packet was invalid + * else length of formatted packet + * + */ +int +scsp_format_msg(dcsp, msg, bpp) + Scsp_dcs *dcsp; + Scsp_msg *msg; + char **bpp; +{ + char *buff = (char *)0, *e_buff = (char *)0; + int buff_len, e_buff_len; + int e_len, len, plen; + struct scsp_nhdr *shp; + Scsp_ext *exp; + + /* + * Allocate a buffer for the message + */ + buff_len = dcsp->sd_server->ss_mtu; + buff = (char *)UM_ALLOC(buff_len); + if (!buff) { + scsp_mem_err("scsp_format_msg: dcsp->sd_server->ss_mtu"); + } + UM_ZERO(buff, buff_len); + *bpp = buff; + + /* + * Encode the fixed header + * + * Set the version + */ + shp = (struct scsp_nhdr *)buff; + shp->sh_ver = SCSP_VER_1; + + /* + * Set the message type + */ + shp->sh_type = msg->sc_msg_type; + + /* + * Point past the fixed header + */ + len = sizeof(struct scsp_nhdr); + buff_len -= len; + + /* + * Encode any extensions into a temporary buffer + */ + e_len = 0; + if (msg->sc_ext) { + /* + * Get a buffer for the extensions + */ + e_buff_len = 1024; + e_buff = (char *)UM_ALLOC(e_buff_len); + if (!buff) { + scsp_mem_err("scsp_format_msg: e_buff_len"); + } + UM_ZERO(e_buff, e_buff_len); + + /* + * Encode the extensions + */ + for (exp = msg->sc_ext = 0; exp; exp = exp->next) { + plen = scsp_format_ext(exp, e_buff + e_len, + e_buff_len - e_len); + if (plen == 0) { + goto ignore; + } + e_len += plen; + } + + /* + * Free the buffer if we didn't use it + */ + if (!e_len) { + UM_FREE(e_buff); + e_buff = (char *)0; + } + } + buff_len -= e_len; + + /* + * Encode the body of the message, depending on the type + */ + switch(msg->sc_msg_type) { + case SCSP_CA_MSG: + plen = scsp_format_ca(msg->sc_ca, buff + len, buff_len); + break; + case SCSP_CSU_REQ_MSG: + case SCSP_CSU_REPLY_MSG: + case SCSP_CSUS_MSG: + plen = scsp_format_csu(msg->sc_csu_msg, buff + len, + buff_len); + break; + case SCSP_HELLO_MSG: + plen = scsp_format_hello(msg->sc_hello, buff + len, + buff_len); + break; + default: + goto ignore; + } + if (plen == 0) { + goto ignore; + } + len += plen; + + /* + * Copy the extensions to the end of the message + */ + if (e_len) { + shp->sh_ext_off = htons(len); + UM_COPY(e_buff, buff + len, e_len); + UM_FREE(e_buff); + } + + /* + * Set the length + */ + shp->sh_len = htons(len); + + /* + * Compute the message checksum + */ + shp->sh_checksum = htons(ip_checksum(buff, len)); + + /* + * Return the length of the buffer + */ + return(len); + +ignore: + if (buff) + UM_FREE(buff); + if (e_buff) + UM_FREE(e_buff); + *bpp = (char *)0; + return(0); +} + + +/* + * Send an SCSP message + * + * Arguments: + * dcsp pointer to DCS control block + * msg pointer to message to send + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_send_msg(dcsp, msg) + Scsp_dcs *dcsp; + Scsp_msg *msg; +{ + int len, rc; + char *buff; + + /* + * Make sure we have a socket open + */ + if (dcsp->sd_sock == -1) { + return(EBADF); + } + + /* + * Trace the message + */ + if (((scsp_trace_mode & SCSP_TRACE_HELLO_MSG) && + msg->sc_msg_type == SCSP_HELLO_MSG) || + ((scsp_trace_mode & SCSP_TRACE_CA_MSG) && + msg->sc_msg_type != SCSP_HELLO_MSG)) { + scsp_trace_msg(dcsp, msg, 0); + scsp_trace("\n"); + } + + /* + * Put the message into network format + */ + len = scsp_format_msg(dcsp, msg, &buff); + if (len == 0) { + scsp_log(LOG_ERR, "scsp_send_msg: message conversion failed\n"); + abort(); + } + + /* + * Write the message to the DCS + */ + rc = write(dcsp->sd_sock, (void *)buff, len); + UM_FREE(buff); + if (rc == len || (rc == -1 && errno == EINPROGRESS)) { + rc = 0; + } else { + /* + * There was an error on the write--close the VCC + */ + (void)close(dcsp->sd_sock); + dcsp->sd_sock = -1; + + /* + * Inform the Hello FSM + */ + (void)scsp_hfsm(dcsp, SCSP_HFSM_VC_CLOSED, + (Scsp_msg *)0); + + /* + * Set the return code + */ + if (rc == -1) + rc = errno; + else + rc = EINVAL; + } + + return(rc); +} diff --git a/usr.sbin/atm/scspd/scsp_print.c b/usr.sbin/atm/scspd/scsp_print.c new file mode 100644 index 0000000..4655077 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_print.c @@ -0,0 +1,1315 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: scsp_print.c,v 1.5 1998/08/13 20:11:16 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * Print routines + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_print.c,v 1.5 1998/08/13 20:11:16 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" + + +/* + * Indent string + */ +#define MIN_INDENT 2 +#define MAX_INDENT 64 +static char indent[MAX_INDENT + 1]; + + +/* + * Value-name translation table entry + */ +struct type_name { + char *name; + u_char type; +}; +typedef struct type_name Type_name; + + +/* + * SCSP name-type tables + */ +static Type_name if_msg_types[] = { + { "Config Request", SCSP_CFG_REQ }, + { "Config Response", SCSP_CFG_RSP }, + { "Cache Indication", SCSP_CACHE_IND }, + { "Cache Response", SCSP_CACHE_RSP }, + { "Solicit Indication", SCSP_SOLICIT_IND }, + { "Solicit Response", SCSP_SOLICIT_RSP }, + { "Cache Update Indication", SCSP_UPDATE_IND }, + { "Cache Update Request", SCSP_UPDATE_REQ }, + { "Cache Update Response", SCSP_UPDATE_RSP }, + { (char *)0, 0 } +}; + +static Type_name msg_types[] = { + { "Cache Alignment", SCSP_CA_MSG }, + { "CSU Request", SCSP_CSU_REQ_MSG }, + { "CSU Reply", SCSP_CSU_REPLY_MSG }, + { "CSU Solicit", SCSP_CSUS_MSG }, + { "Hello", SCSP_HELLO_MSG }, + { (char *)0, 0 } +}; + +static Type_name proto_types[] = { + { "ATMARP", SCSP_PROTO_ATMARP }, + { "NHRP", SCSP_PROTO_NHRP }, + { "MARS", SCSP_PROTO_MARS }, + { "DHCP", SCSP_PROTO_DHCP }, + { "LNNI", SCSP_PROTO_LNNI }, + { (char *)0, 0 } +}; + +static Type_name ext_types[] = { + { "End of Extensions", SCSP_EXT_END }, + { "Authentication", SCSP_EXT_AUTH }, + { "Vendor Private", SCSP_EXT_VENDOR }, + { (char *)0, 0 } +}; + +static Type_name hfsm_state_names[] = { + { "Down", SCSP_HFSM_DOWN }, + { "Waiting", SCSP_HFSM_WAITING }, + { "Unidirectional", SCSP_HFSM_UNI_DIR }, + { "Bidirectional", SCSP_HFSM_BI_DIR }, + { (char *)0, 0 } +}; + +static Type_name hfsm_event_names[] = { + { "VC open", SCSP_HFSM_VC_ESTAB }, + { "VC closed", SCSP_HFSM_VC_CLOSED }, + { "Hello timer", SCSP_HFSM_HELLO_T }, + { "Receive timer", SCSP_HFSM_RCV_T }, + { "Msg received", SCSP_HFSM_RCVD }, + { (char *)0, 0 } +}; + +static Type_name cafsm_state_names[] = { + { "Down", SCSP_CAFSM_DOWN }, + { "Master/Slave negotiation", SCSP_CAFSM_NEG }, + { "Master", SCSP_CAFSM_MASTER }, + { "Slave", SCSP_CAFSM_SLAVE }, + { "Update cache", SCSP_CAFSM_UPDATE }, + { "Aligned", SCSP_CAFSM_ALIGNED }, + { (char *)0, 0 } +}; + +static Type_name cafsm_event_names[] = { + { "Hello FSM up", SCSP_CAFSM_HELLO_UP }, + { "Hello FSM down", SCSP_CAFSM_HELLO_DOWN }, + { "CA received", SCSP_CAFSM_CA_MSG }, + { "CSU Solicit received", SCSP_CAFSM_CSUS_MSG }, + { "CSU Request received", SCSP_CAFSM_CSU_REQ }, + { "CSU Reply received", SCSP_CAFSM_CSU_REPLY }, + { "CA timer", SCSP_CAFSM_CA_T }, + { "CSUS timer", SCSP_CAFSM_CSUS_T }, + { "CSU timer", SCSP_CAFSM_CSU_T }, + { "Cache Update", SCSP_CAFSM_CACHE_UPD }, + { "Cache Response", SCSP_CAFSM_CACHE_RSP }, + { (char *)0, 0 } +}; + +static Type_name cifsm_state_names[] = { + { "Null", SCSP_CIFSM_NULL }, + { "Summarize", SCSP_CIFSM_SUM }, + { "Update", SCSP_CIFSM_UPD }, + { "Aligned", SCSP_CIFSM_ALIGN }, + { (char *)0, 0 } +}; + +static Type_name cifsm_event_names[] = { + { "CA FSM down", SCSP_CIFSM_CA_DOWN }, + { "CA FSM to Summarize",SCSP_CIFSM_CA_SUMM }, + { "CA FSM to Update", SCSP_CIFSM_CA_UPD }, + { "CA FSM to Aligned", SCSP_CIFSM_CA_ALIGN }, + { "Solicit Rsp", SCSP_CIFSM_SOL_RSP }, + { "Update Req", SCSP_CIFSM_UPD_REQ }, + { "Update Rsp", SCSP_CIFSM_UPD_RSP }, + { "CSU Request", SCSP_CIFSM_CSU_REQ }, + { "CSU Reply", SCSP_CIFSM_CSU_REPLY }, + { "CSU Solicit", SCSP_CIFSM_CSU_SOL }, + { (char *)0, 0 } +}; + +static Type_name atmarp_state_names[] = { + { "New", SCSP_ASTATE_NEW }, + { "Updated", SCSP_ASTATE_UPD }, + { "Deleted", SCSP_ASTATE_DEL }, + { (char *)0, 0 } +}; + + +/* + * Initialize the indent string + * + * Arguments: + * none + * + * Returns: + * none + * + */ +static void +init_indent() +{ + indent[0] = '\0'; +} + + +/* + * Increment the indent string + * + * Arguments: + * none + * + * Returns: + * none + * + */ +static void +inc_indent() +{ + if (strlen(indent) >= MAX_INDENT) + return; + strcat(indent, " "); +} + + +/* + * Decrement the indent string + * + * Arguments: + * none + * + * Returns: + * none + * + */ +static void +dec_indent() +{ + if (strlen(indent) < MIN_INDENT) + return; + indent[strlen(indent) - 2] = '\0'; +} + + + +/* + * Search for a type in a name-type table + * + * Arguments: + * type the value being searched for + * tbl pointer to the table to search + * + * Returns: + * pointer to a string identifying the type + * + */ +static char * +scsp_type_name(type, tbl) + u_char type; + Type_name *tbl; +{ + int i; + + /* + * Search the table + */ + for (i = 0; tbl[i].name != (char *)0 && tbl[i].type != type; + i++) + ; + + /* + * Check the result and return the appropriate value + */ + if (tbl[i].name) + return(tbl[i].name); + else + return("-"); +} + + +/* + * Format a Hello FSM state name + * + * Arguments: + * state the state + * + * Returns: + * pointer to a string identifying the state + * + */ +char * +format_hfsm_state(state) + int state; +{ + return(scsp_type_name((u_char)state, hfsm_state_names)); +} + + +/* + * Format a Hello FSM event name + * + * Arguments: + * event the event + * + * Returns: + * pointer to a string identifying the event + * + */ +char * +format_hfsm_event(event) + int event; +{ + char *cp; + + cp = scsp_type_name((u_char)event, hfsm_event_names); + return(cp); +} + + +/* + * Format a CA FSM state name + * + * Arguments: + * state the state + * + * Returns: + * pointer to a string identifying the state + * + */ +char * +format_cafsm_state(state) + int state; +{ + return(scsp_type_name((u_char)state, cafsm_state_names)); +} + + +/* + * Format a CA FSM event name + * + * Arguments: + * event the event + * + * Returns: + * pointer to a string identifying the event + * + */ +char * +format_cafsm_event(event) + int event; +{ + return(scsp_type_name((u_char)event, cafsm_event_names)); +} + + +/* + * Format a client interface FSM state name + * + * Arguments: + * state the state + * + * Returns: + * pointer to a string identifying the state + * + */ +char * +format_cifsm_state(state) + int state; +{ + return(scsp_type_name((u_char)state, cifsm_state_names)); +} + + +/* + * Format a client interface FSM event name + * + * Arguments: + * event the event + * + * Returns: + * pointer to a string identifying the event + * + */ +char * +format_cifsm_event(event) + int event; +{ + return(scsp_type_name((u_char)event, cifsm_event_names)); +} + + +/* + * Print a Sender or Receiver ID structure + * + * Arguments: + * fp file to print message to + * idp pointer to ID to be printed + * + * Returns: + * none + * + */ +void +print_scsp_id(fp, idp) + FILE *fp; + Scsp_id *idp; +{ + int i; + + inc_indent(); + fprintf(fp, "%sNext: 0x%x\n", indent, + (u_long)idp->next); + fprintf(fp, "%sLength: %d\n", indent, + idp->id_len); + fprintf(fp, "%sID: 0x", indent); + for (i = 0; i < idp->id_len; i++) + fprintf(fp, "%02x ", idp->id[i]); + fprintf(fp, "\n"); + dec_indent(); +} + + +/* + * Print a Cache Key structure + * + * Arguments: + * fp file to print message to + * ckp pointer to cache key structure + * + * Returns: + * none + * + */ +void +print_scsp_cache_key(fp, ckp) + FILE *fp; + Scsp_ckey *ckp; +{ + int i; + + inc_indent(); + fprintf(fp, "%sLength: %d\n", indent, + ckp->key_len); + fprintf(fp, "%sKey: 0x", indent); + for (i = 0; i < ckp->key_len; i++) + fprintf(fp, "%02x ", ckp->key[i]); + fprintf(fp, "\n"); + dec_indent(); +} + + +/* + * Print the mandatory common part of a message + * + * Arguments: + * fp file to print message to + * mcp pointer to mandatory common part structure + * + * Returns: + * none + * + */ +static void +print_scsp_mcp(fp, mcp) + FILE *fp; + Scsp_mcp *mcp; +{ + inc_indent(); + fprintf(fp, "%sProtocol ID: %s (0x%02x)\n", indent, + scsp_type_name(mcp->pid, proto_types), + mcp->pid); + fprintf(fp, "%sServer Group ID: %d\n", indent, mcp->sgid); + fprintf(fp, "%sFlags: 0x%04x\n", indent, + mcp->flags); + fprintf(fp, "%sRecord Count: %d\n", indent, + mcp->rec_cnt); + fprintf(fp, "%sSender ID:\n", indent); + print_scsp_id(fp, &mcp->sid); + fprintf(fp, "%sReceiver ID:\n", indent); + print_scsp_id(fp, &mcp->rid); + dec_indent(); +} + + +/* + * Print an extension + * + * Arguments: + * fp file to print message to + * exp pointer to extension + * + * Returns: + * none + * + */ +static void +print_scsp_ext(fp, exp) + FILE *fp; + Scsp_ext *exp; +{ + int i; + u_char *cp; + + inc_indent(); + fprintf(fp, "%sNext: 0x%x\n", indent, + exp->next); + fprintf(fp, "%sType: %s (0x%02x)\n", indent, + scsp_type_name(exp->type, ext_types), + exp->type); + fprintf(fp, "%sLength: %d\n", indent, exp->len); + if (exp->len) { + fprintf(fp, "%sValue: 0x", indent); + cp = (u_char *)((caddr_t)exp + sizeof(Scsp_ext)); + for (i = 0; i < exp->len; i++) + fprintf(fp, "%02x ", *cp++); + fprintf(fp, "\n"); + } + dec_indent(); +} + + +/* + * Print an ATMARP Cache State Advertisement record + * + * Arguments: + * fp file to print message to + * acsp pointer to extension + * + * Returns: + * none + * + */ +static void +print_scsp_atmarp_csa(fp, acsp) + FILE *fp; + Scsp_atmarp_csa *acsp; +{ + inc_indent(); + fprintf(fp, "%sState: %s (%d)\n", indent, + scsp_type_name(acsp->sa_state, + atmarp_state_names), + acsp->sa_state); + fprintf(fp, "%sSource ATM addr: %s\n", indent, + format_atm_addr(&acsp->sa_sha)); + fprintf(fp, "%sSource ATM subaddr: %s\n", indent, + format_atm_addr(&acsp->sa_ssa)); + fprintf(fp, "%sSource IP addr: %s\n", indent, + format_ip_addr(&acsp->sa_spa)); + fprintf(fp, "%sTarget ATM addr: %s\n", indent, + format_atm_addr(&acsp->sa_tha)); + fprintf(fp, "%sTarget ATM subaddr: %s\n", indent, + format_atm_addr(&acsp->sa_tsa)); + fprintf(fp, "%sTarget IP addr: %s\n", indent, + format_ip_addr(&acsp->sa_tpa)); + dec_indent(); +} + + +/* + * Print a Cache State Advertisement record or + * Cache State Advertisement Summary record + * + * Arguments: + * fp file to print message to + * csap pointer to CSA or CSAS + * + * Returns: + * none + * + */ +static void +print_scsp_csa(fp, csap) + FILE *fp; + Scsp_csa *csap; +{ + inc_indent(); + fprintf(fp, "%sNext: 0x%x\n", indent, + (u_long)csap->next); + fprintf(fp, "%sHops: %d\n", indent, csap->hops); + fprintf(fp, "%sNull Flag: %s\n", indent, + csap->null ? "True" : "False"); + fprintf(fp, "%sSequence no.: %d (0x%x)\n", + indent, csap->seq, csap->seq); + fprintf(fp, "%sCache Key:\n", indent); + print_scsp_cache_key(fp, &csap->key); + fprintf(fp, "%sOriginator ID:\n", indent); + print_scsp_id(fp, &csap->oid); + if (csap->atmarp_data) { + fprintf(fp, "%sATMARP data:\n", indent); + print_scsp_atmarp_csa(fp, csap->atmarp_data); + } + dec_indent(); +} + + +/* + * Print a Cache Alignment message + * + * Arguments: + * fp file to print message to + * cap pointer to extension + * + * Returns: + * none + * + */ +static void +print_scsp_ca(fp, cap) + FILE *fp; + Scsp_ca *cap; +{ + int n; + Scsp_csa *csap; + + inc_indent(); + fprintf(fp, "%sCA Seq. No.: %d\n", indent, + cap->ca_seq); + fprintf(fp, "%sM bit: %s\n", indent, + cap->ca_m ? "True" : "False"); + fprintf(fp, "%sI bit: %s\n", indent, + cap->ca_i ? "True" : "False"); + fprintf(fp, "%sO bit: %s\n", indent, + cap->ca_o ? "True" : "False"); + fprintf(fp, "%sMandatory Common Part:\n", indent); + print_scsp_mcp(fp, &cap->ca_mcp); + for (csap = cap->ca_csa_rec, n = 1; csap; + csap = csap->next, n++) { + fprintf(fp, "%sCSA Record %d (0x%x):\n", indent, n, + (u_long)csap); + print_scsp_csa(fp, csap); + } + dec_indent(); +} + + +/* + * Print a Cache State Update Request, Cache State Update Reply, or + * Cache State Update Solicit message + * + * Arguments: + * fp file to print message to + * csup pointer to CSU message + * + * Returns: + * none + * + */ +static void +print_scsp_csu(fp, csup) + FILE *fp; + Scsp_csu_msg *csup; +{ + int i; + Scsp_csa *csap; + + inc_indent(); + fprintf(fp, "%sMandatory Common Part:\n", indent); + print_scsp_mcp(fp, &csup->csu_mcp); + for (csap = csup->csu_csa_rec, i = 1; csap; + csap = csap->next, i++) { + fprintf(fp, "%sCSA Record %d:\n", indent, i); + print_scsp_csa(fp, csap); + } + dec_indent(); +} + + +/* + * Print a Hello message + * + * Arguments: + * fp file to print message to + * hp pointer to hello message + * + * Returns: + * none + * + */ +static void +print_scsp_hello(fp, hp) + FILE *fp; + Scsp_hello *hp; +{ + Scsp_id *ridp; + + inc_indent(); + fprintf(fp, "%sHello Interval: %d\n", indent, + hp->hello_int); + fprintf(fp, "%sDead Factor: %d\n", indent, + hp->dead_factor); + fprintf(fp, "%sFamily ID: %d\n", indent, + hp->family_id); + fprintf(fp, "%sMandatory Common Part:\n", indent); + print_scsp_mcp(fp, &hp->hello_mcp); + ridp = hp->hello_mcp.rid.next; + if (ridp) { + fprintf(fp, "%sAdditional Receiver IDs:\n", indent); + for (; ridp; ridp = ridp->next) + print_scsp_id(fp, ridp); + } + dec_indent(); +} + + +#ifdef NOTDEF +/* + * NHRP-specific Cache State Advertisement record + */ +struct scsp_nhrp_csa { + u_char req_id; /* Request ID */ + u_char state; /* State */ + u_char pref_len; /* Prefix length */ + u_short flags; /* See below */ + u_short mtu; /* Maximim transmission unit */ + u_short hold_time; /* Entry holding time */ + u_char caddr_tlen; /* Client addr type/length */ + u_char csaddr_tlen; /* Client subaddr type/length */ + u_char cproto_len; /* Client proto addr length */ + u_char pref; /* Preference */ + Atm_addr caddr; /* Client address */ + Atm_addr csaddr; /* Client subaddress */ + struct in_addr cproto_addr; /* Client protocol address */ +}; +typedef struct scsp_nhrp Scsp_nhrp; + +#define SCSP_NHRP_UNIQ 0x8000 +#define SCSP_NHRP_ARP 0x4000 + +#endif + + +/* + * Print an SCSP message + * + * Arguments: + * fp file to print message to + * msg pointer to message to be printed + * + * Returns: + * none + * + */ +void +print_scsp_msg(fp, msg) + FILE *fp; + Scsp_msg *msg; +{ + int n; + Scsp_ext *exp; + + /* + * Initialize + */ + init_indent(); + + /* + * Print the message type + */ + inc_indent(); + fprintf(fp, "%sMessage type: %s (0x%02x)\n", indent, + scsp_type_name(msg->sc_msg_type, msg_types), + msg->sc_msg_type); + + /* + * Print the body of the message + */ + switch(msg->sc_msg_type) { + case SCSP_CA_MSG: + print_scsp_ca(fp, msg->sc_ca); + break; + case SCSP_CSU_REQ_MSG: + case SCSP_CSU_REPLY_MSG: + case SCSP_CSUS_MSG: + print_scsp_csu(fp, msg->sc_csu_msg); + break; + case SCSP_HELLO_MSG: + print_scsp_hello(fp, msg->sc_hello); + break; + } + + /* + * Print any extensions + */ + for (exp = msg->sc_ext, n = 1; exp; exp = exp->next, n++) { + fprintf(fp, "%sExtension %d:\n", indent, n); + print_scsp_ext(fp, exp); + } + dec_indent(); + + (void)fflush(fp); +} + + +/* + * Print an SCSP ATMARP message + * + * Arguments: + * fp file to print message to + * acp pointer to ATMARP message + * + * Returns: + * none + * + */ +static void +print_scsp_if_atmarp(fp, amp) + FILE *fp; + Scsp_atmarp_msg *amp; +{ + inc_indent(); + fprintf(fp, "%sState: %s (%d)\n", indent, + scsp_type_name(amp->sa_state, + atmarp_state_names), + amp->sa_state); + fprintf(fp, "%sCached protocol addr: %s\n", indent, + format_ip_addr(&->sa_cpa)); + fprintf(fp, "%sCached ATM addr: %s\n", indent, + format_atm_addr(&->sa_cha)); + fprintf(fp, "%sCached ATM subaddr: %s\n", indent, + format_atm_addr(&->sa_csa)); + fprintf(fp, "%sCache key:\n", indent); + print_scsp_cache_key(fp, &->sa_key); + fprintf(fp, "%sOriginator ID:\n", indent); + print_scsp_id(fp, &->sa_oid); + fprintf(fp, "%sSequence number: %d (0x%08x)\n", indent, + amp->sa_seq, (u_long)amp->sa_seq); + dec_indent(); +} + + +/* + * Print an SCSP client interface message + * + * Arguments: + * fp file to print message to + * imsg pointer to message to be printed + * + * Returns: + * none + * + */ +void +print_scsp_if_msg(fp, imsg) + FILE *fp; + Scsp_if_msg *imsg; +{ + int len; + Scsp_atmarp_msg *ap; + + /* + * Initialize + */ + init_indent(); + fprintf(fp, "SCSP Client Interface Message at 0x%x\n", + (u_long)imsg); + + /* + * Print the message header + */ + inc_indent(); + fprintf(fp, "%sMessage type: %s (0x%02x)\n", indent, + scsp_type_name(imsg->si_type, if_msg_types), + imsg->si_type); + fprintf(fp, "%sResponse code: %d\n", indent, + imsg->si_rc); + fprintf(fp, "%sProtocol type: %s (%d)\n", indent, + scsp_type_name(imsg->si_proto, proto_types), + imsg->si_proto); + fprintf(fp, "%sLength: %d\n", indent, + imsg->si_len); + fprintf(fp, "%sToken: 0x%x\n", indent, + imsg->si_tok); + + /* + * Print the body of the message + */ + switch(imsg->si_type) { + case SCSP_CFG_REQ: + fprintf(fp, "%sInterface: %s\n", indent, + imsg->si_cfg.atmarp_netif); + break; + case SCSP_CACHE_RSP: + case SCSP_UPDATE_IND: + case SCSP_UPDATE_REQ: + len = imsg->si_len - sizeof(Scsp_if_msg_hdr); + ap = &imsg->si_atmarp; + while (len) { + switch(imsg->si_proto) { + case SCSP_PROTO_ATMARP: + fprintf(fp, "%sATMARP CSA:\n", indent); + print_scsp_if_atmarp(fp, ap); + len -= sizeof(Scsp_atmarp_msg); + ap++; + break; + case SCSP_PROTO_NHRP: + case SCSP_PROTO_MARS: + case SCSP_PROTO_DHCP: + case SCSP_PROTO_LNNI: + default: + fprintf(fp, "Protocol type not implemented\n"); + break; + } + } + break; + } + dec_indent(); + + (void)fflush(fp); +} + + +/* + * Print an SCSP pending connection block + * + * Arguments: + * fp file to print message to + * pp pointer to pending control block + * + * Returns: + * none + * + */ +void +print_scsp_pending(fp, pp) + FILE *fp; + Scsp_pending *pp; +{ + /* + * Initialize + */ + init_indent(); + + /* + * Print a header + */ + fprintf(fp, "Pending control block at 0x%x\n", (u_long)pp); + + /* + * Print the fields of the control block + */ + inc_indent(); + fprintf(fp, "%sNext: 0x%x\n", indent, + (u_long)pp->sp_next); + fprintf(fp, "%sSocket: %d\n", indent, + pp->sp_sock); + + dec_indent(); +} + + +/* + * Print an SCSP server control block + * + * Arguments: + * fp file to print message to + * ssp pointer to server control block + * + * Returns: + * none + * + */ +void +print_scsp_server(fp, ssp) + FILE *fp; + Scsp_server *ssp; +{ + /* + * Initialize + */ + init_indent(); + + /* + * Print a header + */ + fprintf(fp, "Server control block at 0x%x\n", (u_long)ssp); + + /* + * Print the fields of the client control block + */ + inc_indent(); + fprintf(fp, "%sNext: 0x%x\n", indent, + ssp->ss_next); + fprintf(fp, "%sName: %s\n", indent, + ssp->ss_name); + fprintf(fp, "%sNetwork Interface: %s\n", indent, + ssp->ss_intf); + fprintf(fp, "%sState: %d\n", indent, + ssp->ss_state); + fprintf(fp, "%sProtocol ID: 0x%x\n", indent, + ssp->ss_pid); + fprintf(fp, "%sID length: %d\n", indent, + ssp->ss_id_len); + fprintf(fp, "%sCache key length: %d\n", indent, + ssp->ss_ckey_len); + fprintf(fp, "%sServer Group ID: 0x%x\n", indent, + ssp->ss_sgid); + fprintf(fp, "%sFamily ID: 0x%x\n", indent, + ssp->ss_fid); + fprintf(fp, "%sSocket: %d\n", indent, + ssp->ss_sock); + fprintf(fp, "%sDCS Listen Socket: %d\n", indent, + ssp->ss_dcs_lsock); + fprintf(fp, "%sLocal Server ID:\n", indent); + print_scsp_id(fp, &ssp->ss_lsid); + fprintf(fp, "%sATM address: %s\n", indent, + format_atm_addr(&ssp->ss_addr)); + fprintf(fp, "%sATM subaddress: %s\n", indent, + format_atm_addr(&ssp->ss_subaddr)); + fprintf(fp, "%sInterface MTU: %d\n", indent, + ssp->ss_mtu); + fprintf(fp, "%sMark: %d\n", indent, + ssp->ss_mark); + dec_indent(); +} + + +/* + * Print an SCSP client cache summary entry control block + * + * Arguments: + * fp file to print message to + * csep pointer to summary entry + * + * Returns: + * none + * + */ +void +print_scsp_cse(fp, csep) + FILE *fp; + Scsp_cse *csep; +{ + /* + * Print the fields of the cache summary entry + */ + inc_indent(); + fprintf(fp, "%sNext CSE: 0x%x\n", indent, + (u_long)csep->sc_next); + fprintf(fp, "%sCSA sequence no.: %d (0x%x)\n", indent, + csep->sc_seq, csep->sc_seq); + fprintf(fp, "%sCache key:\n", indent); + print_scsp_cache_key(fp, &csep->sc_key); + fprintf(fp, "%sOrigin ID:\n", indent); + print_scsp_id(fp, &csep->sc_oid); + dec_indent(); +} + + +/* + * Print an SCSP CSU Request retransmission control block + * + * Arguments: + * fp file to print message to + * csurp pointer to retransmission entry + * + * Returns: + * none + * + */ +void +print_scsp_csu_rexmt(fp, rxp) + FILE *fp; + Scsp_csu_rexmt *rxp; +{ + int i; + Scsp_csa *csap; + + inc_indent(); + fprintf(fp, "%sNext CSU Req rexmt: 0x%x\n", indent, + (u_long)rxp->sr_next); + fprintf(fp, "%sDCS address: 0x%x\n", indent, + (u_long)rxp->sr_dcs); + for (csap = rxp->sr_csa, i = 1; csap; + csap = csap->next, i++) { + fprintf(fp, "%sCSA %d:\n", indent, i); + print_scsp_csa(fp, csap); + } + dec_indent(); +} + + +/* + * Print an SCSP DCS control block + * + * Arguments: + * fp file to print message to + * dcsp pointer to DCS control block + * + * Returns: + * none + * + */ +void +print_scsp_dcs(fp, dcsp) + FILE *fp; + Scsp_dcs *dcsp; +{ + Scsp_csa *csap; + Scsp_cse *csep; + Scsp_csu_rexmt *rxp; + + /* + * Initialize + */ + init_indent(); + + /* + * Print a header + */ + fprintf(fp, "DCS control block at 0x%x\n", (u_long)dcsp); + + /* + * Print the fields of the DCS control block + */ + inc_indent(); + fprintf(fp, "%sNext DCS block: 0x%x\n", indent, + (u_long)dcsp->sd_next); + fprintf(fp, "%sServer control block: 0x%x\n", indent, + (u_long)dcsp->sd_server); + fprintf(fp, "%sDCS ID:\n", indent); + print_scsp_id(fp, &dcsp->sd_dcsid); + fprintf(fp, "%sDCS address: %s\n", indent, + format_atm_addr(&dcsp->sd_addr)); + fprintf(fp, "%sDCS subaddress %s\n", indent, + format_atm_addr(&dcsp->sd_subaddr)); + fprintf(fp, "%sSocket: %d\n", indent, + dcsp->sd_sock); + fprintf(fp, "%sOpen VCC Retry Timer:\n", indent); + fprintf(fp, "%sHello FSM State: %s\n", indent, + format_hfsm_state(dcsp->sd_hello_state)); + fprintf(fp, "%sHello Interval: %d\n", indent, + dcsp->sd_hello_int); + fprintf(fp, "%sHello Dead Factor: %d\n", indent, + dcsp->sd_hello_df); + fprintf(fp, "%sHello Rcvd: %d\n", indent, + dcsp->sd_hello_rcvd); + fprintf(fp, "%sCA FSM State: %s\n", indent, + format_cafsm_state(dcsp->sd_ca_state)); + fprintf(fp, "%sCA Seq. No.: 0x%x\n", indent, + dcsp->sd_ca_seq); + fprintf(fp, "%sCA Rexmit Int: %d\n", indent, + dcsp->sd_ca_rexmt_int); + fprintf(fp, "%sCA Retransmit Msg: 0x%x\n", indent, + (u_long)dcsp->sd_ca_rexmt_msg); + fprintf(fp, "%sCSASs to send: ", indent); + if (dcsp->sd_ca_csas == (Scsp_cse *)0) { + fprintf(fp, "Empty\n"); + } else { + fprintf(fp, "0x%x\n", (u_long) dcsp->sd_ca_csas); + } + fprintf(fp, "%sCSUS Rexmit Int: %d\n", indent, + dcsp->sd_csus_rexmt_int); + fprintf(fp, "%sCache Request List: ", indent); + if (dcsp->sd_crl == (Scsp_csa *)0) { + fprintf(fp, "Empty\n"); + } else { + fprintf(fp, "0x%x\n", dcsp->sd_crl); + } + fprintf(fp, "%sCSUS Rexmit Msg: 0x%x\n", indent, + (u_long)dcsp->sd_csus_rexmt_msg); + fprintf(fp, "%sCSA Hop count: %d\n", indent, + dcsp->sd_hops); + fprintf(fp, "%sCSAs Pending ACK: 0x%x\n", indent, + (u_long)dcsp->sd_csu_ack_pend); + fprintf(fp, "%sCSAs ACKed: 0x%x\n", indent, + (u_long)dcsp->sd_csu_ack); + fprintf(fp, "%sCSU Req Rexmit Int: %d\n", indent, + dcsp->sd_csu_rexmt_int); + fprintf(fp, "%sCSU Req Rexmit Max: %d\n", indent, + dcsp->sd_csu_rexmt_max); + fprintf(fp, "%sCSU Req Rexmit Queue ", indent); + if (!dcsp->sd_csu_rexmt) { + fprintf(fp, "Empty\n"); + } else { + fprintf(fp, "0x%x\n", (u_long)dcsp->sd_csu_rexmt); + } + fprintf(fp, "%sClient I/F state: %d\n", indent, + dcsp->sd_client_state); + + /* + * Print the list of CSASs waiting to be sent + */ + if (dcsp->sd_ca_csas) { + fprintf(fp, "\n%sCSASs to send:", indent); + inc_indent(); + for (csep = dcsp->sd_ca_csas; csep; + csep = csep->sc_next) { + fprintf(fp, "%sCache summary entry at 0x%x\n", + indent, + (u_long)csep); + print_scsp_cse(fp, csep); + } + dec_indent(); + } + + /* + * Print the Cache Request List + */ + if (dcsp->sd_crl) { + fprintf(fp, "\n%sCache Request List:\n", indent); + inc_indent(); + for (csap = dcsp->sd_crl; csap; csap = csap->next) { + fprintf(fp, "%sCSA at 0x%x\n", indent, + (u_long)csap); + print_scsp_csa(fp, csap); + } + dec_indent(); + } + + /* + * Print the CSU retransmit queue + */ + if (dcsp->sd_csu_rexmt) { + fprintf(fp, "\n%sCSU Req Rexmit Queue:\n", indent); + inc_indent(); + for (rxp = dcsp->sd_csu_rexmt; rxp; + rxp = rxp->sr_next) { + fprintf(fp, "%sCSU Rexmit Block at 0x%x\n", + indent, (u_long)csap); + print_scsp_csu_rexmt(fp, rxp); + } + dec_indent(); + } + + dec_indent(); +} + + +/* + * Print SCSP's control blocks + * + * Arguments: + * none + * + * Returns: + * None + * + */ +void +print_scsp_dump() +{ + int i; + Scsp_server *ssp; + Scsp_dcs *dcsp; + Scsp_cse *scp; + Scsp_csu_rexmt *rxp; + Scsp_pending *pp; + FILE *df; + char fname[64]; + static int dump_no = 0; + + /* + * Build a file name + */ + UM_ZERO(fname, sizeof(fname)); + sprintf(fname, "/tmp/scspd.%d.%03d.out", getpid(), dump_no++); + + /* + * Open the output file + */ + df = fopen(fname, "w"); + if (df == (FILE *)0) + return; + + /* + * Dump the server control blocks + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + print_scsp_server(df, ssp); + fprintf(df, "\n"); + + /* + * Print the client's cache summary + */ + for (i = 0; i < SCSP_HASHSZ; i++) { + for (scp = ssp->ss_cache[i]; scp; + scp = scp->sc_next) { + print_scsp_cse(df, scp); + fprintf(df, "\n"); + } + } + + /* + * Print the client's DCS control blocks + */ + for (dcsp = ssp->ss_dcs; dcsp; dcsp = dcsp->sd_next) { + print_scsp_dcs(df, dcsp); + fprintf(df, "\n\n"); + } + fprintf(df, "\n\n"); + } + + /* + * Print the pending connection blocks + */ + for (pp = scsp_pending_head; pp; pp = pp->sp_next) { + print_scsp_pending(df, pp); + fprintf(df, "\n"); + } + + /* + * Close the output file + */ + (void)fclose(df); +} diff --git a/usr.sbin/atm/scspd/scsp_socket.c b/usr.sbin/atm/scspd/scsp_socket.c new file mode 100644 index 0000000..83f41cd --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_socket.c @@ -0,0 +1,1349 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: scsp_socket.c,v 1.6 1998/08/21 18:08:24 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP socket management routines + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_socket.c,v 1.6 1998/08/21 18:08:24 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" + + +/* + * Local variables + */ +static struct t_atm_llc llc_scsp = { + T_ATM_LLC_SHARING, + 8, + {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x5e, 0x00, 0x05} +}; + +static struct t_atm_aal5 aal5 = { + 0, /* forward_max_SDU_size */ + 0, /* backward_max_SDU_size */ + 0 /* SSCS_type */ +}; + +static struct t_atm_traffic traffic = { + { /* forward */ + T_ATM_ABSENT, /* PCR_high_priority */ + 0, /* PCR_all_traffic */ + T_ATM_ABSENT, /* SCR_high_priority */ + T_ATM_ABSENT, /* SCR_all_traffic */ + T_ATM_ABSENT, /* MBS_high_priority */ + T_ATM_ABSENT, /* MBS_all_traffic */ + T_NO /* tagging */ + }, + { /* backward */ + T_ATM_ABSENT, /* PCR_high_priority */ + 0, /* PCR_all_traffic */ + T_ATM_ABSENT, /* SCR_high_priority */ + T_ATM_ABSENT, /* SCR_all_traffic */ + T_ATM_ABSENT, /* MBS_high_priority */ + T_ATM_ABSENT, /* MBS_all_traffic */ + T_NO /* tagging */ + }, + T_YES /* best_effort */ +}; + +static struct t_atm_bearer bearer = { + T_ATM_CLASS_X, /* bearer_class */ + T_ATM_NULL, /* traffic_type */ + T_ATM_NULL, /* timing_requirements */ + T_NO, /* clipping_susceptibility */ + T_ATM_1_TO_1 /* connection_configuration */ +}; + +static struct t_atm_qos qos = { + T_ATM_NETWORK_CODING, /* coding_standard */ + { /* forward */ + T_ATM_QOS_CLASS_0 /* qos_class */ + }, + { /* backward */ + T_ATM_QOS_CLASS_0 /* qos_class */ + } +}; + +static struct t_atm_app_name appname = { + "SCSP" +}; + + +/* + * Find a DCS, given its socket + * + * Arguments: + * sd socket descriptor + * + * Returns: + * 0 not found + * address of DCS block corresponding to socket + * + */ +Scsp_dcs * +scsp_find_dcs(sd) + int sd; +{ + Scsp_server *ssp; + Scsp_dcs *dcsp; + + /* + * Loop through the list of servers + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + /* + * Check all the DCSs chained from each server + */ + for (dcsp = ssp->ss_dcs; dcsp; dcsp = dcsp->sd_next) { + if (dcsp->sd_sock == sd) + break; + } + } + + return(dcsp); +} + + +/* + * Find a server, given its socket + * + * Arguments: + * sd socket descriptor + * + * Returns: + * 0 not found + * address of server block corresponding to socket + * + */ +Scsp_server * +scsp_find_server(sd) + int sd; +{ + Scsp_server *ssp; + + /* + * Loop through the list of servers + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + if (ssp->ss_sock == sd) + break; + } + + return(ssp); +} + + +/* + * Connect to a directly connected server + * + * Arguments: + * dcsp pointer to DCS block for server + * + * Returns: + * 0 success (dcsp->sd_sock is set) + * else errno indicating reason for failure + * + */ +int +scsp_dcs_connect(dcsp) + Scsp_dcs *dcsp; + +{ + int rc, sd; + struct sockaddr_atm DCS_addr; + + /* + * If the DCS already has an open connection, just return + */ + if (dcsp->sd_sock != -1) { + return(0); + } + + /* + * Open an ATM socket + */ + sd = socket(PF_ATM, SOCK_SEQPACKET, ATM_PROTO_AAL5); + if (sd == -1) { + return(ESOCKTNOSUPPORT); + } + if (sd > scsp_max_socket) { + scsp_max_socket = sd; + } + + /* + * Set up connection parameters for SCSP connection + */ + UM_ZERO(&DCS_addr, sizeof(DCS_addr)); +#if (defined(BSD) && (BSD >= 199103)) + DCS_addr.satm_len = sizeof(DCS_addr); +#endif + DCS_addr.satm_family = AF_ATM; + DCS_addr.satm_addr.t_atm_sap_addr.SVE_tag_addr = + T_ATM_PRESENT; + DCS_addr.satm_addr.t_atm_sap_addr.SVE_tag_selector = + T_ATM_PRESENT; + DCS_addr.satm_addr.t_atm_sap_addr.address_format = + dcsp->sd_addr.address_format; + DCS_addr.satm_addr.t_atm_sap_addr.address_length = + dcsp->sd_addr.address_length; + UM_COPY(dcsp->sd_addr.address, + DCS_addr.satm_addr.t_atm_sap_addr.address, + dcsp->sd_addr.address_length); + + DCS_addr.satm_addr.t_atm_sap_layer2.SVE_tag = + T_ATM_PRESENT; + DCS_addr.satm_addr.t_atm_sap_layer2.ID_type = + T_ATM_SIMPLE_ID; + DCS_addr.satm_addr.t_atm_sap_layer2.ID.simple_ID = + T_ATM_BLLI2_I8802; + + DCS_addr.satm_addr.t_atm_sap_layer3.SVE_tag = + T_ATM_ABSENT; + DCS_addr.satm_addr.t_atm_sap_appl.SVE_tag = + T_ATM_ABSENT; + + /* + * Bind the socket to our address + */ + if (bind(sd, (struct sockaddr *)&DCS_addr, + sizeof(DCS_addr))) { + rc = errno; + goto connect_fail; + } + + /* + * Set non-blocking operation + */ +#ifdef sun + rc = fcntl(sd, F_SETFL, FNBIO + FNDELAY); +#else + rc = fcntl(sd, F_SETFL, O_NONBLOCK); +#endif + if (rc == -1) { + scsp_log(LOG_ERR, "scsp_dcs_connect: fcntl failed"); + rc = errno; + goto connect_fail; + } + + /* + * Set AAL 5 options + */ + aal5.forward_max_SDU_size = dcsp->sd_server->ss_mtu; + aal5.backward_max_SDU_size = dcsp->sd_server->ss_mtu; + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_AAL5, (caddr_t)&aal5, + sizeof(aal5)) < 0) { + rc = EOPNOTSUPP; + goto connect_fail; + } + + /* + * Set traffic options + */ + switch(dcsp->sd_server->ss_media) { + case MEDIA_TAXI_100: + traffic.forward.PCR_all_traffic = ATM_PCR_TAXI100; + traffic.backward.PCR_all_traffic = ATM_PCR_TAXI100; + break; + case MEDIA_TAXI_140: + traffic.forward.PCR_all_traffic = ATM_PCR_TAXI140; + traffic.backward.PCR_all_traffic = ATM_PCR_TAXI140; + break; + case MEDIA_OC3C: + case MEDIA_UTP155: + traffic.forward.PCR_all_traffic = ATM_PCR_OC3C; + traffic.backward.PCR_all_traffic = ATM_PCR_OC3C; + break; + case MEDIA_OC12C: + traffic.forward.PCR_all_traffic = ATM_PCR_OC12C; + traffic.backward.PCR_all_traffic = ATM_PCR_OC12C; + break; + } + + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_TRAFFIC, + (caddr_t)&traffic, sizeof(traffic)) < 0) { + rc = EOPNOTSUPP; + goto connect_fail; + } + + /* + * Set bearer capability options + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_BEARER_CAP, + (caddr_t)&bearer, sizeof(bearer)) < 0) { + rc = EOPNOTSUPP; + goto connect_fail; + } + + /* + * Set QOS options + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_QOS, + (caddr_t)&qos, sizeof(qos)) < 0) { + rc = EOPNOTSUPP; + goto connect_fail; + } + + /* + * Set LLC identifier + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_LLC, + (caddr_t)&llc_scsp, sizeof(llc_scsp)) < 0) { + rc = EOPNOTSUPP; + goto connect_fail; + } + + /* + * Set application name + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_APP_NAME, + (caddr_t)&appname, sizeof(appname)) < 0) { + rc = EOPNOTSUPP; + goto connect_fail; + } + + /* + * Connect to DCS + */ + if (connect(sd, (struct sockaddr *)&DCS_addr, + sizeof(DCS_addr)) < 0 && + errno != EINPROGRESS) { + rc = errno; + goto connect_fail; + } + + /* + * Set return values + */ + dcsp->sd_sock = sd; + return(0); + +connect_fail: + /* + * Close the socket if something didn't work + */ + (void)close(sd); + dcsp->sd_sock = -1; + if (rc == 0) + rc = EFAULT; + return(rc); +} + + +/* + * Listen for ATM connections from DCSs + * + * Arguments: + * None + * + * Returns: + * sock socket which is listening (also set in + ssp->ss_dcs_lsock) + * -1 error encountered (reason in errno) + * + */ +int +scsp_dcs_listen(ssp) + Scsp_server *ssp; +{ + int rc, sd; + struct sockaddr_atm ls_addr; + + /* + * Open a socket + */ + sd = socket(PF_ATM, SOCK_SEQPACKET, ATM_PROTO_AAL5); + if (sd == -1) { + rc = errno; + goto listen_fail; + } + if (sd > scsp_max_socket) { + scsp_max_socket = sd; + } + + /* + * Set up our address + */ + UM_ZERO(&ls_addr, sizeof(ls_addr)); +#if (defined(BSD) && (BSD >= 199103)) + ls_addr.satm_len = sizeof(ls_addr); +#endif + ls_addr.satm_family = AF_ATM; + ls_addr.satm_addr.t_atm_sap_addr.SVE_tag_addr = T_ATM_PRESENT; + ls_addr.satm_addr.t_atm_sap_addr.SVE_tag_selector = + T_ATM_PRESENT; + ls_addr.satm_addr.t_atm_sap_addr.address_format = + ssp->ss_addr.address_format; + ls_addr.satm_addr.t_atm_sap_addr.address_length = + ssp->ss_addr.address_length; + UM_COPY(ssp->ss_addr.address, + ls_addr.satm_addr.t_atm_sap_addr.address, + ssp->ss_addr.address_length); + + ls_addr.satm_addr.t_atm_sap_layer2.SVE_tag = T_ATM_PRESENT; + ls_addr.satm_addr.t_atm_sap_layer2.ID_type = T_ATM_SIMPLE_ID; + ls_addr.satm_addr.t_atm_sap_layer2.ID.simple_ID = + T_ATM_BLLI2_I8802; + + ls_addr.satm_addr.t_atm_sap_layer3.SVE_tag = T_ATM_ABSENT; + ls_addr.satm_addr.t_atm_sap_appl.SVE_tag = T_ATM_ABSENT; + + /* + * Bind the socket to our address + */ + rc = bind(sd, (struct sockaddr *)&ls_addr, sizeof(ls_addr)); + if (rc == -1) { + rc = errno; + goto listen_fail; + } + + /* + * Set non-blocking I/O + */ +#ifdef sun + rc = fcntl(sd, F_SETFL, FNBIO + FNDELAY); +#else + rc = fcntl(sd, F_SETFL, O_NONBLOCK); +#endif + if (rc == -1) { + scsp_log(LOG_ERR, "scsp_dcs_listen: fcntl failed"); + rc = errno; + goto listen_fail; + } + + /* + * Set AAL 5 options + */ + aal5.forward_max_SDU_size = ssp->ss_mtu; + aal5.backward_max_SDU_size = ssp->ss_mtu; + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_AAL5, (caddr_t)&aal5, + sizeof(aal5)) < 0) { + rc = EOPNOTSUPP; + goto listen_fail; + } + + /* + * Set traffic options + */ + switch(ssp->ss_media) { + case MEDIA_TAXI_100: + traffic.forward.PCR_all_traffic = ATM_PCR_TAXI100; + traffic.backward.PCR_all_traffic = ATM_PCR_TAXI100; + break; + case MEDIA_TAXI_140: + traffic.forward.PCR_all_traffic = ATM_PCR_TAXI140; + traffic.backward.PCR_all_traffic = ATM_PCR_TAXI140; + break; + case MEDIA_OC3C: + case MEDIA_UTP155: + traffic.forward.PCR_all_traffic = ATM_PCR_OC3C; + traffic.backward.PCR_all_traffic = ATM_PCR_OC3C; + break; + case MEDIA_OC12C: + traffic.forward.PCR_all_traffic = ATM_PCR_OC12C; + traffic.backward.PCR_all_traffic = ATM_PCR_OC12C; + break; + } + + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_TRAFFIC, + (caddr_t)&traffic, sizeof(traffic)) < 0) { + rc = EOPNOTSUPP; + goto listen_fail; + } + + /* + * Set bearer capability options + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_BEARER_CAP, + (caddr_t)&bearer, sizeof(bearer)) < 0) { + rc = EOPNOTSUPP; + goto listen_fail; + } + + /* + * Set QOS options + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_QOS, + (caddr_t)&qos, sizeof(qos)) < 0) { + rc = EOPNOTSUPP; + goto listen_fail; + } + + /* + * Set LLC identifier + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_LLC, + (caddr_t)&llc_scsp, sizeof(llc_scsp)) < 0) { + rc = EOPNOTSUPP; + goto listen_fail; + } + + /* + * Set application name + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_APP_NAME, + (caddr_t)&appname, sizeof(appname)) < 0) { + rc = EOPNOTSUPP; + goto listen_fail; + } + + /* + * Listen for new connections + */ + if (listen(sd, 5) < 0) { + rc = errno; + goto listen_fail; + } + + ssp->ss_dcs_lsock = sd; + return(sd); + +listen_fail: + /* + * Close the socket if anything didn't work + */ + (void)close(sd); + if (rc == 0) + errno = EFAULT; + else + errno = rc; + ssp->ss_dcs_lsock = -1; + return(-1); +} + + +/* + * Accept a connection from a DCS + * + * Arguments: + * ssp pointer to server block + * + * Returns: + * address of DCS with new connection + * 0 failure (errno has reason) + * + */ +Scsp_dcs * +scsp_dcs_accept(ssp) + Scsp_server *ssp; +{ + int len, rc, sd; + struct sockaddr_atm dcs_sockaddr; + struct t_atm_sap_addr *dcs_addr = &dcs_sockaddr.satm_addr.t_atm_sap_addr; + Atm_addr dcs_atmaddr; + Scsp_dcs *dcsp; + + /* + * Accept the new connection + */ + len = sizeof(dcs_sockaddr); + sd = accept(ssp->ss_dcs_lsock, + (struct sockaddr *)&dcs_sockaddr, &len); + if (sd < 0) { + return((Scsp_dcs *)0); + } + if (sd > scsp_max_socket) { + scsp_max_socket = sd; + } + + /* + * Copy the DCS's address from the sockaddr to an Atm_addr + */ + if (dcs_addr->SVE_tag_addr != T_ATM_PRESENT) { + dcs_atmaddr.address_format = T_ATM_ABSENT; + dcs_atmaddr.address_length = 0; + } else { + dcs_atmaddr.address_format = dcs_addr->address_format; + dcs_atmaddr.address_length = dcs_addr->address_length; + UM_COPY(dcs_addr->address, dcs_atmaddr.address, + dcs_addr->address_length); + } + + /* + * Find out which DCS this connection is for + */ + for (dcsp = ssp->ss_dcs; dcsp; dcsp = dcsp->sd_next) { + /* + * Compare DCS's address to address + * configured by user + */ + if (ATM_ADDR_EQUAL(&dcsp->sd_addr, + &dcs_atmaddr)) + break; + } + + /* + * Make sure we have this DCS configured + */ + if (!dcsp) { + errno = EINVAL; + goto dcs_accept_fail; + } + + /* + * Make sure we are in a state to accept the connection + */ + if (ssp->ss_state != SCSP_SS_ACTIVE) { + errno = EACCES; + goto dcs_accept_fail; + } + + /* + * Make sure we don't already have a connection to this DCS + */ + if (dcsp->sd_sock != -1) { + errno = EALREADY; + goto dcs_accept_fail; + } + + /* + * Set application name + */ + if (setsockopt(sd, T_ATM_SIGNALING, T_ATM_APP_NAME, + (caddr_t)&appname, sizeof(appname)) < 0) { + rc = EOPNOTSUPP; + goto dcs_accept_fail; + } + + /* + * Set non-blocking I/O + */ +#ifdef sun + rc = fcntl(sd, F_SETFL, FNBIO + FNDELAY); +#else + rc = fcntl(sd, F_SETFL, O_NONBLOCK); +#endif + if (rc == -1) { + goto dcs_accept_fail; + } + + /* + * Cancel the open retry timer + */ + HARP_CANCEL(&dcsp->sd_open_t); + + /* + * Save the socket address and return the + * address of the DCS + */ + dcsp->sd_sock = sd; + return(dcsp); + +dcs_accept_fail: + /* + * An error has occured--clean up and return + */ + (void)close(sd); + return((Scsp_dcs *)0); +} + + +/* + * Read an SCSP message from a directly connected server + * + * Arguments: + * dcsp pointer to DCS block that has data + * + * Returns: + * 0 success + * else errno indicating reason for failure + * + */ +int +scsp_dcs_read(dcsp) + Scsp_dcs *dcsp; + +{ + int len, rc; + char *buff = (char *)0; + Scsp_server *ssp = dcsp->sd_server; + Scsp_msg *msg; + struct scsp_nhdr msg_hdr, *mhp; + + /* + * Get a buffer to hold the entire message + */ + len = ssp->ss_mtu; + buff = (char *)UM_ALLOC(len); + if (!buff) { + scsp_mem_err("scsp_dcs_read: ssp->ss_mtu"); + } + + /* + * Read the message + */ + len = read(dcsp->sd_sock, buff, len); + if (len < 0) { + goto dcs_read_fail; + } + + /* + * Parse the input message and pass it to the Hello FSM + */ + msg = scsp_parse_msg(buff, len); + if (msg) { + /* + * Write the message to the trace file if + * it's of a type we're tracing + */ + if (((scsp_trace_mode & SCSP_TRACE_HELLO_MSG) && + msg->sc_msg_type == SCSP_HELLO_MSG) || + ((scsp_trace_mode & SCSP_TRACE_CA_MSG) && + msg->sc_msg_type != SCSP_HELLO_MSG)) { + scsp_trace_msg(dcsp, msg, 1); + scsp_trace("\n"); + } + + /* + * Pass the message to the Hello FSM + */ + rc = scsp_hfsm(dcsp, SCSP_HFSM_RCVD, msg); + scsp_free_msg(msg); + } else { + /* + * Message was invalid. Write it to the trace file + * if we're tracing messages. + */ + if (scsp_trace_mode & (SCSP_TRACE_HELLO_MSG & + SCSP_TRACE_CA_MSG)) { + int i; + scsp_trace("Invalid message received:\n"); + scsp_trace("0x"); + for (i = 0; i < len; i++) { + scsp_trace("%02x ", (u_char)buff[i]); + } + scsp_trace("\n"); + } + } + UM_FREE(buff); + + return(0); + +dcs_read_fail: + /* + * Error on read--check for special conditions + */ + rc = errno; + if (errno == ECONNRESET) { + /* + * VCC has been closed--pass the event to + * the Hello FSM + */ + rc = scsp_hfsm(dcsp, SCSP_HFSM_VC_CLOSED, + (Scsp_msg *)0); + } + if (errno == ECONNREFUSED) { + /* + * VCC open failed--set a timer and try + * again when it fires + */ + HARP_TIMER(&dcsp->sd_open_t, + SCSP_Open_Interval, + scsp_open_timeout); + rc = 0; + } + + if (buff) + UM_FREE(buff); + return(rc); +} + + +/* + * Listen for Unix connections from SCSP client servers + * + * Arguments: + * None + * + * Returns: + * sock socket which is listening + * -1 error (reason in errno) + * + */ +int +scsp_server_listen() +{ + int rc, sd; + + static struct sockaddr scsp_addr = { +#if (defined(BSD) && (BSD >= 199103)) + sizeof(struct sockaddr), /* sa_len */ +#endif + AF_UNIX, /* sa_family */ + SCSPD_SOCK_NAME /* sa_data */ + }; + + /* + * Unlink any old socket + */ + rc = unlink(SCSPD_SOCK_NAME); + if (rc < 0 && errno != ENOENT) + return(-1); + + /* + * Open a socket + */ + sd = socket(PF_UNIX, SOCK_STREAM, 0); + if (sd == -1) { + return(-1); + } + if (sd > scsp_max_socket) { + scsp_max_socket = sd; + } + + /* + * Bind the socket's address + */ + rc = bind(sd, &scsp_addr, sizeof(scsp_addr)); + if (rc == -1) { + (void)close(sd); + return(-1); + } + + /* + * Set non-blocking I/O + */ +#ifdef sun + rc = fcntl(sd, F_SETFL, FNBIO + FNDELAY); +#else + rc = fcntl(sd, F_SETFL, O_NONBLOCK); +#endif + if (rc == -1) { + (void)close(sd); + return(-1); + } + + /* + * Listen for new connections + */ + if (listen(sd, 5) < 0) { + (void)close(sd); + return(-1); + } + + return(sd); +} + + +/* + * Accept a connection from a server + * + * We accept a connection, but we won't know which server it is + * from until we get the configuration data from the server. We + * put the connection on a 'pending' queue and will assign it to + * a server when the config data arrives. + * + * Arguments: + * ls listening socket to accept from + * + * Returns: + * 0 success + * errno reason for failure + * + */ +int +scsp_server_accept(ls) + int ls; + +{ + int len, rc, sd; + struct sockaddr server_addr; + Scsp_pending *psp; + + /* + * Accept the new connection + */ + len = sizeof(server_addr); + sd = accept(ls, (struct sockaddr *)&server_addr, &len); + if (sd < 0) { + return(errno); + } + if (sd > scsp_max_socket) { + scsp_max_socket = sd; + } + + /* + * Set non-blocking operation + */ +#ifdef sun + rc = fcntl(sd, F_SETFL, FNBIO + FNDELAY); +#else + rc = fcntl(sd, F_SETFL, O_NONBLOCK); +#endif + if (rc == -1) { + (void)close(sd); + rc = errno; + } + + /* + * Put the new socket on the 'pending' queue + */ + psp = (Scsp_pending *) UM_ALLOC(sizeof(Scsp_pending)); + if (!psp) { + scsp_mem_err("scsp_server_accept: sizeof(Scsp_pending)"); + } + psp->sp_sock = sd; + LINK2TAIL(psp, Scsp_pending, scsp_pending_head, sp_next); + + return(0); +} + + +/* + * Read a server interface message from a socket + * + * Arguments: + * sd socket to read from + * + * Returns: + * msg pointer to message read + * 0 failure (errno has reason) + * + */ +Scsp_if_msg * +scsp_if_sock_read(sd) + int sd; + +{ + int len, rc; + char *buff = (char *)0; + Scsp_if_msg *msg; + Scsp_if_msg_hdr msg_hdr; + + /* + * Read the message header from the socket + */ + len = read(sd, (char *)&msg_hdr, sizeof(msg_hdr)); + if (len != sizeof(msg_hdr)) { + if (len >= 0) + errno = EINVAL; + goto socket_read_fail; + } + + /* + * Get a buffer and read the rest of the message into it + */ + buff = (char *)UM_ALLOC(msg_hdr.sh_len); + if (!buff) { + scsp_mem_err("scsp_if_sock_read: msg_hdr.sh_len"); + } + msg = (Scsp_if_msg *)buff; + msg->si_hdr = msg_hdr; + len = read(sd, &buff[sizeof(Scsp_if_msg_hdr)], + msg->si_len - sizeof(Scsp_if_msg_hdr)); + if (len != msg->si_len - sizeof(Scsp_if_msg_hdr)) { + if (len >= 0) { + errno = EINVAL; + } + goto socket_read_fail; + } + + /* + * Trace the message + */ + if (scsp_trace_mode & SCSP_TRACE_IF_MSG) { + scsp_trace("Received server I/F message:\n"); + print_scsp_if_msg(scsp_trace_file, msg); + scsp_trace("\n"); + } + + return(msg); + +socket_read_fail: + if (buff) + UM_FREE(buff); + return((Scsp_if_msg *)0); +} + + +/* + * Write a server interface message to a socket + * + * Arguments: + * sd socket to write to + * msg pointer to message to write + * + * Returns: + * 0 success + * errno reason for failure + * + */ +int +scsp_if_sock_write(sd, msg) + int sd; + Scsp_if_msg *msg; +{ + int len, rc; + + /* + * Trace the message + */ + if (scsp_trace_mode & SCSP_TRACE_IF_MSG) { + scsp_trace("Writing server I/F message:\n"); + print_scsp_if_msg(scsp_trace_file, msg); + scsp_trace("\n"); + } + + /* + * Write the message to the indicated socket + */ + len = write(sd, (char *)msg, msg->si_len); + if (len != msg->si_len) { + if (len < 0) + rc = errno; + else + rc = EINVAL; + } else { + rc = 0; + } + + return(rc); +} + + +/* + * Read data from a local server + * + * Arguments: + * ssp pointer to server block that has data + * + * Returns: + * 0 success + * else errno indicating reason for failure + * + */ +int +scsp_server_read(ssp) + Scsp_server *ssp; +{ + int rc; + Scsp_dcs *dcsp; + Scsp_if_msg *msg; + + /* + * Read the message + */ + msg = scsp_if_sock_read(ssp->ss_sock); + if (!msg) { + if (errno == EWOULDBLOCK) { + /* + * Nothing to read--just return + */ + return(0); + } else { + /* + * Error--shut down the server entry + */ + scsp_server_shutdown(ssp); + } + return(errno); + } + + /* + * Process the received message + */ + switch(msg->si_type) { + case SCSP_NOP_REQ: + /* + * Ignore a NOP + */ + break; + case SCSP_CACHE_RSP: + /* + * Summarize the server's cache and try to open + * connections to all of its DCSs + */ + scsp_process_cache_rsp(ssp, msg); + ssp->ss_state = SCSP_SS_ACTIVE; + for (dcsp = ssp->ss_dcs; dcsp; dcsp = dcsp->sd_next) { + if (scsp_dcs_connect(dcsp)) { + /* + * Connect failed -- the DCS may not + * be up yet, so we'll try again later + */ + HARP_TIMER(&dcsp->sd_open_t, + SCSP_Open_Interval, + scsp_open_timeout); + } + } + ssp->ss_state = SCSP_SS_ACTIVE; + break; + case SCSP_SOLICIT_RSP: + /* + * The server has answered our request for a particular + * entry from its cache + */ + dcsp = (Scsp_dcs *)msg->si_tok; + rc = scsp_cfsm(dcsp, SCSP_CIFSM_SOL_RSP, (Scsp_msg *)0, + msg); + break; + case SCSP_UPDATE_REQ: + /* + * Pass the update request to the FSMs for all + * DCSs associated with the server + */ + if (ssp->ss_state == SCSP_SS_ACTIVE) { + for (dcsp = ssp->ss_dcs; dcsp; + dcsp = dcsp->sd_next) { + rc = scsp_cfsm(dcsp, SCSP_CIFSM_UPD_REQ, + (Scsp_msg *)0, msg); + } + } + break; + case SCSP_UPDATE_RSP: + /* + * Pass the update response to the FSM for the + * DCS associated with the request + */ + dcsp = (Scsp_dcs *)msg->si_tok; + rc = scsp_cfsm(dcsp, SCSP_CIFSM_UPD_RSP, + (Scsp_msg *)0, msg); + break; + default: + scsp_log(LOG_ERR, "invalid message type %d from server", + msg->si_type); + return(EINVAL); + } + + UM_FREE(msg); + return(0); +} + + +/* + * Send a Cache Indication to a server + * + * Arguments: + * ssp pointer to server block block + * + * Returns: + * 0 success + * else errno indicating reason for failure + * + */ +int +scsp_send_cache_ind(ssp) + Scsp_server *ssp; +{ + int rc; + Scsp_if_msg *msg; + + /* + * Get storage for a server interface message + */ + msg = (Scsp_if_msg *)UM_ALLOC(sizeof(Scsp_if_msg)); + if (!msg) { + scsp_mem_err("scsp_send_cache_ind: sizeof(Scsp_if_msg)"); + } + UM_ZERO(msg, sizeof(Scsp_if_msg)); + + /* + * Fill out the message + */ + msg->si_type = SCSP_CACHE_IND; + msg->si_rc = 0; + msg->si_proto = ssp->ss_pid; + msg->si_len = sizeof(Scsp_if_msg_hdr); + msg->si_tok = (u_long)ssp; + + /* + * Send the message + */ + rc = scsp_if_sock_write(ssp->ss_sock, msg); + UM_FREE(msg); + return(rc); +} + + +/* + * Read data from a pending server connection + * + * Arguments: + * psp pointer to pending block that has data + * + * Returns: + * 0 success + * else errno indicating reason for failure + * + */ +int +scsp_pending_read(psp) + Scsp_pending *psp; + +{ + int rc; + Scsp_server *ssp; + Scsp_dcs *dcsp; + Scsp_if_msg *msg; + + /* + * Read the message from the pending socket + */ + msg = scsp_if_sock_read(psp->sp_sock); + if (!msg) { + rc = errno; + goto pending_read_fail; + } + + /* + * Make sure this is configuration data + */ + if (msg->si_type != SCSP_CFG_REQ) { + scsp_log(LOG_ERR, "invalid message type %d from pending server", + msg->si_type); + rc = EINVAL; + goto pending_read_fail; + } + + /* + * Find the server this message is for + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + if (strcmp(ssp->ss_intf, msg->si_cfg.atmarp_netif) == 0) + break; + } + if (!ssp) { + scsp_log(LOG_ERR, "refused connection from server for %s", + msg->si_cfg.atmarp_netif); + rc = EINVAL; + goto config_reject; + } + + /* + * Make sure the server is ready to go + */ + rc = scsp_get_server_info(ssp); + if (rc) { + goto config_reject; + } + + /* + * Save the socket + */ + ssp->ss_sock = psp->sp_sock; + ssp->ss_state = SCSP_SS_CFG; + UNLINK(psp, Scsp_pending, scsp_pending_head, sp_next); + UM_FREE(psp); + + /* + * Listen for connections from the server's DCSs + */ + rc = scsp_dcs_listen(ssp); + if (rc < 0) { + rc = errno; + goto config_reject; + } + + /* + * Respond to the configuration message + */ + msg->si_type = SCSP_CFG_RSP; + msg->si_rc = SCSP_RSP_OK; + msg->si_len = sizeof(Scsp_if_msg_hdr); + rc = scsp_if_sock_write(ssp->ss_sock, msg); + if (rc) { + goto config_error;; + } + + /* + * Ask the server to send us its cache + */ + rc = scsp_send_cache_ind(ssp); + if (rc) { + goto config_error; + } + + UM_FREE(msg); + return(0); + +config_reject: + /* + * Respond to the configuration message + */ + msg->si_type = SCSP_CFG_RSP; + msg->si_rc = SCSP_RSP_REJ; + msg->si_len = sizeof(Scsp_if_msg_hdr); + (void)scsp_if_sock_write(ssp->ss_sock, msg); + +config_error: + if (ssp->ss_sock != -1) { + (void)close(ssp->ss_sock); + ssp->ss_sock = -1; + } + if (ssp->ss_dcs_lsock != -1) { + (void)close(ssp->ss_dcs_lsock); + ssp->ss_sock = -1; + } + ssp->ss_state = SCSP_SS_NULL; + UM_FREE(msg); + + return(rc); + +pending_read_fail: + /* + * Close the socket and free the pending read block + */ + (void)close(psp->sp_sock); + UNLINK(psp, Scsp_pending, scsp_pending_head, sp_next); + UM_FREE(psp); + if (msg) + UM_FREE(msg); + return(rc); +} diff --git a/usr.sbin/atm/scspd/scsp_subr.c b/usr.sbin/atm/scspd/scsp_subr.c new file mode 100644 index 0000000..c14195b --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_subr.c @@ -0,0 +1,1123 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: scsp_subr.c,v 1.5 1998/08/13 20:11:16 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP subroutines + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_subr.c,v 1.5 1998/08/13 20:11:16 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/port.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sigmgr.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> +#include <netatm/uni/unisig_var.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" + + +/* + * Hash an SCSP cache key + * + * Arguments: + * ckp pointer to an SCSP cache key structure + * + * Returns: + * hashed value + * + */ +int +scsp_hash(ckp) + Scsp_ckey *ckp; +{ + int i, j, h; + + /* + * Turn cache key into a positive integer + */ + h = 0; + for (i = ckp->key_len-1, j = 0; + i > 0, j < sizeof(int); + i--, j++) + h = (h << 8) + ckp->key[i]; + h = abs(h); + + /* + * Return the hashed value + */ + return(h % SCSP_HASHSZ); +} + + +/* + * Compare two SCSP IDs + * + * Arguments: + * id1p pointer to an SCSP ID structure + * id2p pointer to an SCSP ID structure + * + * Returns: + * < 0 id1 is less than id2 + * 0 id1 and id2 are equal + * > 0 id1 is greater than id2 + * + */ +int +scsp_cmp_id(id1p, id2p) + Scsp_id *id1p; + Scsp_id *id2p; +{ + int diff, i; + + /* + * Compare the two IDs, byte for byte + */ + for (i = 0; i < id1p->id_len && i < id2p->id_len; i++) { + diff = id1p->id[i] - id2p->id[i]; + if (diff) { + return(diff); + } + } + + /* + * IDs are equal. If lengths differ, the longer ID is + * greater than the shorter. + */ + return(id1p->id_len - id2p->id_len); +} + + +/* + * Compare two SCSP cache keys + * + * Arguments: + * ck1p pointer to an SCSP cache key structure + * ck2p pointer to an SCSP cache key structure + * + * Returns: + * < 0 ck1 is less than ck2 + * 0 ck1 and ck2 are equal + * > 0 ck1 is greater than ck2 + * + */ +int +scsp_cmp_key(ck1p, ck2p) + Scsp_ckey *ck1p; + Scsp_ckey *ck2p; +{ + int diff, i; + + /* + * Compare the two keys, byte for byte + */ + for (i = 0; i < ck1p->key_len && i < ck2p->key_len; i++) { + diff = ck1p->key[i] - ck2p->key[i]; + if (diff) + return(diff); + } + + /* + * Keys are equal. If lengths differ, the longer key is + * greater than the shorter. + */ + return(ck1p->key_len - ck2p->key_len); +} + + +/* + * Check whether the host system is an ATMARP server for + * the LIS associated with a given interface + * + * Arguments: + * netif pointer to the network interface name + * + * Returns: + * 1 host is a server + * 0 host is not a server + * + */ +int +scsp_is_atmarp_server(netif) + char *netif; +{ + int rc; + int buf_len = sizeof(struct air_asrv_rsp); + struct atminfreq air; + struct air_asrv_rsp *asrv_info; + + /* + * Get interface information from the kernel + */ + strcpy(air.air_int_intf, netif); + air.air_opcode = AIOCS_INF_ASV; + buf_len = do_info_ioctl(&air, buf_len); + if (buf_len < 0) + return(0); + + /* + * Check the interface's ATMARP server address + */ + asrv_info = (struct air_asrv_rsp *) air.air_buf_addr; + rc = (asrv_info->asp_addr.address_format == T_ATM_ABSENT) && + (asrv_info->asp_subaddr.address_format == + T_ATM_ABSENT); + UM_FREE(asrv_info); + return(rc); +} + + +/* + * Make a copy of a cache summary entry + * + * Arguments: + * csep pointer to CSE entry to copy + * + * Returns: + * 0 copy failed + * else pointer to new CSE entry + * + */ +Scsp_cse * +scsp_dup_cse(csep) + Scsp_cse *csep; +{ + Scsp_cse *dupp; + + /* + * Allocate memory for the duplicate + */ + dupp = (Scsp_cse *)UM_ALLOC(sizeof(Scsp_cse)); + if (!dupp) { + scsp_mem_err("scsp_dup_cse: sizeof(Scsp_cse)"); + } + + /* + * Copy data to the duplicate + */ + UM_COPY(csep, dupp, sizeof(Scsp_cse)); + dupp->sc_next = (Scsp_cse *)0; + + return(dupp); +} + + +/* + * Make a copy of a CSA or CSAS record + * + * Arguments: + * csap pointer to CSE entry to copy + * + * Returns: + * 0 copy failed + * else pointer to new CSA or CSAS record + * + */ +Scsp_csa * +scsp_dup_csa(csap) + Scsp_csa *csap; +{ + Scsp_csa *dupp; + Scsp_atmarp_csa *adp; + + /* + * Allocate memory for the duplicate + */ + dupp = (Scsp_csa *)UM_ALLOC(sizeof(Scsp_csa)); + if (!dupp) { + scsp_mem_err("scsp_dup_csa: sizeof(Scsp_csa)"); + } + + /* + * Copy data to the duplicate + */ + UM_COPY(csap, dupp, sizeof(Scsp_csa)); + dupp->next = (Scsp_csa *)0; + + /* + * Copy protocol-specific data, if it's present + */ + if (csap->atmarp_data) { + adp = (Scsp_atmarp_csa *)UM_ALLOC(sizeof(Scsp_atmarp_csa)); + if (!adp) { + scsp_mem_err("scsp_dup_csa: sizeof(Scsp_atmarp_csa)"); + } + UM_COPY(csap->atmarp_data, adp, sizeof(Scsp_atmarp_csa)); + dupp->atmarp_data = adp; + } + + return(dupp); +} + + +/* + * Copy a cache summary entry into a CSAS + * + * Arguments: + * csep pointer to CSE entry to copy + * + * Returns: + * 0 copy failed + * else pointer to CSAS record summarizing the entry + * + */ +Scsp_csa * +scsp_cse2csas(csep) + Scsp_cse *csep; +{ + Scsp_csa *csap; + + /* + * Allocate memory for the duplicate + */ + csap = (Scsp_csa *)UM_ALLOC(sizeof(Scsp_csa)); + if (!csap) { + scsp_mem_err("scsp_cse2csas: sizeof(Scsp_csa)"); + } + UM_ZERO(csap, sizeof(Scsp_csa)); + + /* + * Copy data to the CSAS entry + */ + csap->seq = csep->sc_seq; + csap->key = csep->sc_key; + csap->oid = csep->sc_oid; + + return(csap); +} + + +/* + * Copy an ATMARP cache entry into a cache summary entry + * + * Arguments: + * aap pointer to ATMARP cache entry to copy + * + * Returns: + * 0 copy failed + * else pointer to CSE record summarizing the entry + * + */ +Scsp_cse * +scsp_atmarp2cse(aap) + Scsp_atmarp_msg *aap; +{ + Scsp_cse *csep; + + /* + * Allocate memory for the duplicate + */ + csep = (Scsp_cse *)UM_ALLOC(sizeof(Scsp_cse)); + if (!csep) { + scsp_mem_err("scsp_atmarp2cse: sizeof(Scsp_cse)"); + } + UM_ZERO(csep, sizeof(Scsp_cse)); + + /* + * Copy data to the CSE entry + */ + csep->sc_seq = aap->sa_seq; + csep->sc_key = aap->sa_key; + csep->sc_oid = aap->sa_oid; + + return(csep); +} + + +/* + * Clean up a DCS block. This routine is called to clear out any + * lingering state information when the CA FSM reverts to an 'earlier' + * state (Down or Master/Slave Negotiation). + * + * Arguments: + * dcsp pointer to a DCS control block for the neighbor + * + * Returns: + * none + * + */ +void +scsp_dcs_cleanup(dcsp) + Scsp_dcs *dcsp; +{ + Scsp_cse *csep, *ncsep; + Scsp_csa *csap, *next_csap; + Scsp_csu_rexmt *rxp, *rx_next; + + /* + * Free any CSAS entries waiting to be sent + */ + for (csep = dcsp->sd_ca_csas; csep; csep = ncsep) { + ncsep = csep->sc_next; + UNLINK(csep, Scsp_cse, dcsp->sd_ca_csas, sc_next); + UM_FREE(csep); + } + + /* + * Free any entries on the CRL + */ + for (csap = dcsp->sd_crl; csap; csap = next_csap) { + next_csap = csap->next; + UNLINK(csap, Scsp_csa, dcsp->sd_crl, next); + SCSP_FREE_CSA(csap); + } + + /* + * Free any saved CA message and cancel the CA + * retransmission timer + */ + if (dcsp->sd_ca_rexmt_msg) { + scsp_free_msg(dcsp->sd_ca_rexmt_msg); + dcsp->sd_ca_rexmt_msg = (Scsp_msg *)0; + } + HARP_CANCEL(&dcsp->sd_ca_rexmt_t); + + /* + * Free any saved CSU Solicit message and cancel the CSUS + * retransmission timer + */ + if (dcsp->sd_csus_rexmt_msg) { + scsp_free_msg(dcsp->sd_csus_rexmt_msg); + dcsp->sd_csus_rexmt_msg = (Scsp_msg *)0; + } + HARP_CANCEL(&dcsp->sd_csus_rexmt_t); + + /* + * Free any entries on the CSU Request retransmission queue + */ + for (rxp = dcsp->sd_csu_rexmt; rxp; rxp = rx_next) { + rx_next = rxp->sr_next; + HARP_CANCEL(&rxp->sr_t); + for (csap = rxp->sr_csa; csap; csap = next_csap) { + next_csap = csap->next; + SCSP_FREE_CSA(csap); + } + UNLINK(rxp, Scsp_csu_rexmt, dcsp->sd_csu_rexmt, + sr_next); + UM_FREE(rxp); + } +} + + +/* + * Delete an SCSP DCS block and any associated information + * + * Arguments: + * dcsp pointer to a DCS control block to delete + * + * Returns: + * none + * + */ +void +scsp_dcs_delete(dcsp) + Scsp_dcs *dcsp; +{ + Scsp_cse *csep, *next_cse; + Scsp_csu_rexmt *rxp, *next_rxp; + Scsp_csa *csap, *next_csa; + + /* + * Cancel any pending DCS timers + */ + HARP_CANCEL(&dcsp->sd_open_t); + HARP_CANCEL(&dcsp->sd_hello_h_t); + HARP_CANCEL(&dcsp->sd_hello_rcv_t); + HARP_CANCEL(&dcsp->sd_ca_rexmt_t); + HARP_CANCEL(&dcsp->sd_csus_rexmt_t); + + /* + * Unlink the DCS block from the server block + */ + UNLINK(dcsp, Scsp_dcs, dcsp->sd_server->ss_dcs, sd_next); + + /* + * Close the VCC to the DCS, if one is open + */ + if (dcsp->sd_sock != -1) { + (void)close(dcsp->sd_sock); + } + + /* + * Free any saved CA message + */ + if (dcsp->sd_ca_rexmt_msg) { + scsp_free_msg(dcsp->sd_ca_rexmt_msg); + } + + /* + * Free any pending CSAs waiting for cache alignment + */ + for (csep = dcsp->sd_ca_csas; csep; csep = next_cse) { + next_cse = csep->sc_next; + UM_FREE(csep); + } + + /* + * Free anything on the cache request list + */ + for (csap = dcsp->sd_crl; csap; csap = next_csa) { + next_csa = csap->next; + SCSP_FREE_CSA(csap); + } + + /* + * Free any saved CSUS message + */ + if (dcsp->sd_csus_rexmt_msg) { + scsp_free_msg(dcsp->sd_csus_rexmt_msg); + } + + /* + * Free anything on the CSU Request retransmit queue + */ + for (rxp = dcsp->sd_csu_rexmt; rxp; rxp = next_rxp) { + /* + * Cancel the retransmit timer + */ + HARP_CANCEL(&rxp->sr_t); + + /* + * Free the CSAs to be retransmitted + */ + for (csap = rxp->sr_csa; csap; csap = next_csa) { + next_csa = csap->next; + SCSP_FREE_CSA(csap); + } + + /* + * Free the CSU Req retransmission control block + */ + next_rxp = rxp->sr_next; + UM_FREE(rxp); + } + + /* + * Free the DCS block + */ + UM_FREE(dcsp); +} + + +/* + * Shut down a server. This routine is called when a connection to + * a server is lost. It will clear the server's state without deleting + * the server. + * + * Arguments: + * ssp pointer to a server control block + * + * Returns: + * none + * + */ +void +scsp_server_shutdown(ssp) + Scsp_server *ssp; +{ + int i; + Scsp_dcs *dcsp; + Scsp_cse *csep; + + /* + * Trace the shutdown + */ + if (scsp_trace_mode & (SCSP_TRACE_IF_MSG | SCSP_TRACE_CFSM)) { + scsp_trace("Server %s being shut down\n", + ssp->ss_name); + } + + /* + * Terminate up all the DCS connections and clean + * up the control blocks + */ + for (dcsp = ssp->ss_dcs; dcsp; dcsp = dcsp->sd_next) { + if (dcsp->sd_sock != -1) { + (void)close(dcsp->sd_sock); + dcsp->sd_sock = -1; + } + HARP_CANCEL(&dcsp->sd_open_t); + HARP_CANCEL(&dcsp->sd_hello_h_t); + HARP_CANCEL(&dcsp->sd_hello_rcv_t); + scsp_dcs_cleanup(dcsp); + dcsp->sd_hello_state = SCSP_HFSM_DOWN; + dcsp->sd_ca_state = SCSP_CAFSM_DOWN; + dcsp->sd_client_state = SCSP_CIFSM_NULL; + } + + /* + * Clean up the server control block + */ + if (ssp->ss_sock != -1) { + (void)close(ssp->ss_sock); + ssp->ss_sock = -1; + } + if (ssp->ss_dcs_lsock != -1) { + (void)close(ssp->ss_dcs_lsock); + ssp->ss_dcs_lsock = -1; + } + ssp->ss_state = SCSP_SS_NULL; + + /* + * Free the entries in the server's summary cache + */ + for (i = 0; i < SCSP_HASHSZ; i++) { + while (ssp->ss_cache[i]) { + csep = ssp->ss_cache[i]; + UNLINK(csep, Scsp_cse, ssp->ss_cache[i], + sc_next); + UM_FREE(csep); + } + } +} + + +/* + * Delete an SCSP server block and any associated information + * + * Arguments: + * ssp pointer to a server control block to delete + * + * Returns: + * none + * + */ +void +scsp_server_delete(ssp) + Scsp_server *ssp; +{ + int i; + Scsp_dcs *dcsp, *next_dcs; + Scsp_cse *csep, *next_cse; + + /* + * Unlink the server block from the chain + */ + UNLINK(ssp, Scsp_server, scsp_server_head, ss_next); + + /* + * Free the DCS blocks associated with the server + */ + for (dcsp = ssp->ss_dcs; dcsp; dcsp = next_dcs) { + next_dcs = dcsp->sd_next; + scsp_dcs_delete(dcsp); + } + + /* + * Free the entries in the server's summary cache + */ + for (i = 0; i < SCSP_HASHSZ; i++) { + for (csep = ssp->ss_cache[i]; csep; csep = next_cse) { + next_cse = csep->sc_next; + UM_FREE(csep); + } + } + + /* + * Free the server block + */ + UM_FREE(ssp->ss_name); + UM_FREE(ssp); +} + + +/* + * Get informtion about a server from the kernel + * + * Arguments: + * ssp pointer to the server block + * + * Returns: + * 0 server info is OK + * errno server is not ready + * + */ +int +scsp_get_server_info(ssp) + Scsp_server *ssp; +{ + int i, len, mtu, rc, sel; + struct atminfreq air; + struct air_netif_rsp *netif_rsp = (struct air_netif_rsp *)0; + struct air_int_rsp *intf_rsp = (struct air_int_rsp *)0; + struct air_cfg_rsp *cfg_rsp = (struct air_cfg_rsp *)0; + struct sockaddr_in *ip_addr; + struct sockaddr_in subnet_mask; + Atm_addr_nsap *anp; + + /* + * Make sure we're the server for the interface + */ + if (!scsp_is_atmarp_server(ssp->ss_intf)) { + rc = EINVAL; + goto server_info_done; + } + + /* + * Get the IP address and physical interface name + * associated with the network interface + */ + UM_ZERO(&air, sizeof(struct atminfreq)); + air.air_opcode = AIOCS_INF_NIF; + strcpy(air.air_netif_intf, ssp->ss_intf); + len = do_info_ioctl(&air, sizeof(struct air_netif_rsp)); + if (len <= 0) { + rc = EIO; + goto server_info_done; + } + netif_rsp = (struct air_netif_rsp *)air.air_buf_addr; + + ip_addr = (struct sockaddr_in *)&netif_rsp->anp_proto_addr; + if (ip_addr->sin_family != AF_INET || + ip_addr->sin_addr.s_addr == 0) { + rc = EADDRNOTAVAIL; + goto server_info_done; + } + + /* + * Get the MTU for the network interface + */ + mtu = get_mtu(ssp->ss_intf); + if (mtu < 0) { + rc = EIO; + goto server_info_done; + } + + /* + * Get the ATM address associated with the + * physical interface + */ + UM_ZERO(&air, sizeof(struct atminfreq)); + air.air_opcode = AIOCS_INF_INT; + strcpy(air.air_int_intf, netif_rsp->anp_phy_intf); + len = do_info_ioctl(&air, sizeof(struct air_int_rsp)); + if (len <= 0) { + rc = EIO; + goto server_info_done; + } + intf_rsp = (struct air_int_rsp *)air.air_buf_addr; + + /* + * Make sure we're running UNI signalling + */ + if (intf_rsp->anp_sig_proto != ATM_SIG_UNI30 && + intf_rsp->anp_sig_proto != ATM_SIG_UNI31 && + intf_rsp->anp_sig_proto != ATM_SIG_UNI40) { + rc = EINVAL; + goto server_info_done; + } + + /* + * Check the physical interface's state + */ + if (intf_rsp->anp_sig_state != UNISIG_ACTIVE) { + rc = EHOSTDOWN; + goto server_info_done; + } + + /* + * Make sure the interface's address is valid + */ + if (intf_rsp->anp_addr.address_format != T_ATM_ENDSYS_ADDR && + !(intf_rsp->anp_addr.address_format == + T_ATM_E164_ADDR && + intf_rsp->anp_subaddr.address_format == + T_ATM_ENDSYS_ADDR)) { + rc = EINVAL; + goto server_info_done; + } + + /* + * Find the selector byte value for the interface + */ + for (i=0; i<strlen(ssp->ss_intf); i++) { + if (ssp->ss_intf[i] >= '0' && + ssp->ss_intf[i] <= '9') + break; + } + sel = atoi(&ssp->ss_intf[i]); + + /* + * Get configuration information associated with the + * physical interface + */ + UM_ZERO(&air, sizeof(struct atminfreq)); + air.air_opcode = AIOCS_INF_CFG; + strcpy(air.air_int_intf, netif_rsp->anp_phy_intf); + len = do_info_ioctl(&air, sizeof(struct air_cfg_rsp)); + if (len <= 0) { + rc = EIO; + goto server_info_done; + } + cfg_rsp = (struct air_cfg_rsp *)air.air_buf_addr; + + /* + * Update the server entry + */ + UM_COPY(&ip_addr->sin_addr, ssp->ss_lsid.id, ssp->ss_id_len); + ssp->ss_lsid.id_len = ssp->ss_id_len; + ssp->ss_mtu = mtu + 8; + ATM_ADDR_COPY(&intf_rsp->anp_addr, &ssp->ss_addr); + ATM_ADDR_COPY(&intf_rsp->anp_subaddr, &ssp->ss_subaddr); + if (ssp->ss_addr.address_format == T_ATM_ENDSYS_ADDR) { + anp = (Atm_addr_nsap *)ssp->ss_addr.address; + anp->aan_sel = sel; + } else if (ssp->ss_addr.address_format == T_ATM_E164_ADDR && + ssp->ss_subaddr.address_format == + T_ATM_ENDSYS_ADDR) { + anp = (Atm_addr_nsap *)ssp->ss_subaddr.address; + anp->aan_sel = sel; + } + ssp->ss_media = cfg_rsp->acp_cfg.ac_media; + rc = 0; + + /* + * Free dynamic data + */ +server_info_done: + if (netif_rsp) + UM_FREE(netif_rsp); + if (intf_rsp) + UM_FREE(intf_rsp); + if (cfg_rsp) + UM_FREE(cfg_rsp); + + return(rc); +} + + +/* + * Process a CA message + * + * Arguments: + * dcsp pointer to a DCS control block for the neighbor + * cap pointer to the CA part of the received message + * + * Returns: + * none + * + */ +void +scsp_process_ca(dcsp, cap) + Scsp_dcs *dcsp; + Scsp_ca *cap; +{ + Scsp_csa *csap, *next_csap; + Scsp_cse *csep; + Scsp_server *ssp = dcsp->sd_server; + + /* + * Process CSAS records from the CA message + */ + for (csap = cap->ca_csa_rec; csap; csap = next_csap) { + next_csap = csap->next; + SCSP_LOOKUP(ssp, &csap->key, csep); + if (!csep || scsp_cmp_id(&csap->oid, + &csep->sc_oid) == 0 && + csap->seq > csep->sc_seq) { + /* + * CSAS entry not in cache or more + * up to date than cache, add it to CRL + */ + UNLINK(csap, Scsp_csa, cap->ca_csa_rec, next); + LINK2TAIL(csap, Scsp_csa, dcsp->sd_crl, next); + } + } +} + + +/* + * Process a Cache Response message from a server + * + * Arguments: + * ssp pointer to the server block + * smp pointer to the message + * + * Returns: + * none + * + */ +void +scsp_process_cache_rsp(ssp, smp) + Scsp_server *ssp; + Scsp_if_msg *smp; +{ + int len; + Scsp_atmarp_msg *aap; + Scsp_cse *csep; + + /* + * Loop through the message, processing each cache entry + */ + len = smp->si_len; + len -= sizeof(Scsp_if_msg_hdr); + aap = &smp->si_atmarp; + while (len > 0) { + switch(smp->si_proto) { + case SCSP_ATMARP_PROTO: + /* + * If we already have an entry with this key, + * delete it + */ + SCSP_LOOKUP(ssp, &aap->sa_key, csep); + if (csep) { + SCSP_DELETE(ssp, csep); + UM_FREE(csep); + } + + /* + * Copy the data from the server to a cache + * summary entry + */ + csep = scsp_atmarp2cse(aap); + + /* + * Point past this entry + */ + len -= sizeof(Scsp_atmarp_msg); + aap++; + break; + case SCSP_NHRP_PROTO: + /* + * Not implemented yet + */ + return; + } + + /* + * Add the new summary entry to the cache + */ + SCSP_ADD(ssp, csep); + } +} + + +/* + * Propagate a CSA to all the DCSs in the server group except + * the one the CSA was received from + * + * Arguments: + * dcsp pointer to a the DCS the CSA came from + * csap pointer to a the CSA + * + * Returns: + * 0 success + * errno error encountered + * + */ +int +scsp_propagate_csa(dcsp, csap) + Scsp_dcs *dcsp; + Scsp_csa *csap; +{ + int rc, ret_rc = 0; + Scsp_server *ssp = dcsp->sd_server; + Scsp_dcs *dcsp1; + Scsp_csa *csap1; + + /* + * Check the hop count in the CSA + */ + if (csap->hops <= 1) + return(0); + + /* + * Pass the cache entry on to the server's other DCSs + */ + for (dcsp1 = ssp->ss_dcs; dcsp1; dcsp1 = dcsp1->sd_next) { + /* + * Skip this DCS if it's the one we got + * the entry from + */ + if (dcsp1 == dcsp) + continue; + + /* + * Copy the CSA + */ + csap1 = scsp_dup_csa(csap); + + /* + * Decrement the hop count + */ + csap1->hops--; + + /* + * Send the copy of the CSA to the CA FSM for the DCS + */ + rc = scsp_cafsm(dcsp1, SCSP_CAFSM_CACHE_UPD, + (void *) csap1); + if (rc) + ret_rc = rc; + } + + return(ret_rc); +} + + +/* + * Update SCSP's cache given a CSA or CSAS + * + * Arguments: + * dcsp pointer to a DCS + * csap pointer to a CSA + * + * Returns: + * none + * + */ +void +scsp_update_cache(dcsp, csap) + Scsp_dcs *dcsp; + Scsp_csa *csap; +{ + Scsp_cse *csep; + + /* + * Check whether we already have this in the cache + */ + SCSP_LOOKUP(dcsp->sd_server, &csap->key, csep); + + /* + * If we don't already have it and it's not being deleted, + * build a new cache summary entry + */ + if (!csep && !csap->null) { + /* + * Get memory for a new entry + */ + csep = (Scsp_cse *)UM_ALLOC(sizeof(Scsp_cse)); + if (!csep) { + scsp_mem_err("scsp_update_cache: sizeof(Scsp_cse)"); + } + UM_ZERO(csep, sizeof(Scsp_cse)); + + /* + * Fill out the new cache summary entry + */ + csep->sc_seq = csap->seq; + csep->sc_key = csap->key; + csep->sc_oid = csap->oid; + + /* + * Add the new entry to the cache + */ + SCSP_ADD(dcsp->sd_server, csep); + } + + /* + * Update or delete the entry + */ + if (csap->null) { + /* + * The null flag is set--delete the entry + */ + if (csep) { + SCSP_DELETE(dcsp->sd_server, csep); + UM_FREE(csep); + } + } else { + /* + * Update the existing entry + */ + csep->sc_seq = csap->seq; + csep->sc_oid = csap->oid; + } +} + + +/* + * Reconfigure SCSP + * + * Called as the result of a SIGHUP interrupt. Reread the + * configuration file and solicit the cache from the server. + * + * Arguments: + * none + * + * Returns: + * none + * + */ +void +scsp_reconfigure() +{ + int rc; + Scsp_server *ssp; + + /* + * Log a message saying we're reconfiguring + */ + scsp_log(LOG_ERR, "Reconfiguring ..."); + + /* + * Re-read the configuration file + */ + rc = scsp_config(scsp_config_file); + if (rc) { + scsp_log(LOG_ERR, "Found %d error%s in configuration file", + rc, ((rc == 1) ? "" : "s")); + exit(1); + } + + /* + * If a connection to a server is open, get the cache from + * the server + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + if (ssp->ss_sock != -1) { + rc = scsp_send_cache_ind(ssp); + } + } +} diff --git a/usr.sbin/atm/scspd/scsp_timer.c b/usr.sbin/atm/scspd/scsp_timer.c new file mode 100644 index 0000000..0ec6169d --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_timer.c @@ -0,0 +1,265 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: scsp_timer.c,v 1.2 1998/07/16 15:59:50 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * Timer processing + * + */ + +#ifndef lint +static char *RCSid = "@(#) $Id: scsp_timer.c,v 1.2 1998/07/16 15:59:50 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <stdio.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" + + +/* + * Process an SCSP Open timeout + * + * The open timer is set when an attempt to open a VCC to a DCS fails. + * This routine will be called when the timer fires and will retry + * the open. Retries can continue indefinitely. + * + * Arguments: + * stp pointer to an SCSP timer block + * + * Returns: + * None + * + */ +void +scsp_open_timeout(stp) + Harp_timer *stp; +{ + Scsp_dcs *dcsp; + + /* + * Back off to start of DCS entry + */ + dcsp = (Scsp_dcs *) ((caddr_t)stp - + (int)(&((Scsp_dcs *)0)->sd_open_t)); + + /* + * Retry the connection + */ + if (scsp_dcs_connect(dcsp)) { + /* + * Connect failed -- we hope the error was temporary + * and set the timer to try again later + */ + HARP_TIMER(&dcsp->sd_open_t, SCSP_Open_Interval, + scsp_open_timeout); + } +} + + +/* + * Process an SCSP Hello timeout + * + * The Hello timer fires every SCSP_HELLO_Interval seconds. This + * routine will notify the Hello FSM when the timer fires. + * + * Arguments: + * stp pointer to an SCSP timer block + * + * Returns: + * None + * + */ +void +scsp_hello_timeout(stp) + Harp_timer *stp; +{ + Scsp_dcs *dcsp; + + /* + * Back off to start of DCS entry + */ + dcsp = (Scsp_dcs *) ((caddr_t)stp - + (int)(&((Scsp_dcs *)0)->sd_hello_h_t)); + + /* + * Call the Hello FSM + */ + (void)scsp_hfsm(dcsp, SCSP_HFSM_HELLO_T, (Scsp_msg *)0); + + return; +} + + +/* + * Process an SCSP receive timeout + * + * The receive timer is started whenever the Hello FSM receives a + * Hello message from its DCS. If the timer fires, it means that no + * Hello messages have been received in the DCS's Hello interval. + * + * Arguments: + * stp pointer to an SCSP timer block + * + * Returns: + * None + * + */ +void +scsp_hello_rcv_timeout(stp) + Harp_timer *stp; +{ + Scsp_dcs *dcsp; + + /* + * Back off to start of DCS entry + */ + dcsp = (Scsp_dcs *) ((caddr_t)stp - + (int)(&((Scsp_dcs *)0)->sd_hello_rcv_t)); + + /* + * Call the Hello FSM + */ + (void)scsp_hfsm(dcsp, SCSP_HFSM_RCV_T, (void *)0); + + return; +} + + +/* + * Process an SCSP CA retransmit timeout + * + * Arguments: + * stp pointer to an SCSP timer block + * + * Returns: + * None + * + */ +void +scsp_ca_retran_timeout(stp) + Harp_timer *stp; +{ + Scsp_dcs *dcsp; + + /* + * Back off to start of DCS entry + */ + dcsp = (Scsp_dcs *) ((caddr_t)stp - + (int)(&((Scsp_dcs *)0)->sd_ca_rexmt_t)); + + /* + * Call the CA FSM + */ + (void)scsp_cafsm(dcsp, SCSP_CAFSM_CA_T, (void *)0); + + return; +} + + +/* + * Process an SCSP CSUS retransmit timeout + * + * Arguments: + * stp pointer to an SCSP timer block + * + * Returns: + * None + * + */ +void +scsp_csus_retran_timeout(stp) + Harp_timer *stp; +{ + Scsp_dcs *dcsp; + + /* + * Back off to start of DCS entry + */ + dcsp = (Scsp_dcs *) ((caddr_t)stp - + (int)(&((Scsp_dcs *)0)->sd_csus_rexmt_t)); + + /* + * Call the CA FSM + */ + (void)scsp_cafsm(dcsp, SCSP_CAFSM_CSUS_T, (void *)0); + + return; +} + + +/* + * Process an SCSP CSU Req retransmit timeout + * + * Arguments: + * stp pointer to an SCSP timer block + * + * Returns: + * None + * + */ +void +scsp_csu_req_retran_timeout(stp) + Harp_timer *stp; +{ + Scsp_csu_rexmt *rxp; + Scsp_dcs *dcsp; + + /* + * Back off to start of CSU Request retransmission entry + */ + rxp = (Scsp_csu_rexmt *) ((caddr_t)stp - + (int)(&((Scsp_csu_rexmt *)0)->sr_t)); + dcsp = rxp->sr_dcs; + + /* + * Call the CA FSM + */ + (void)scsp_cafsm(dcsp, SCSP_CAFSM_CSU_T, (void *)rxp); + + return; +} diff --git a/usr.sbin/atm/scspd/scsp_var.h b/usr.sbin/atm/scspd/scsp_var.h new file mode 100644 index 0000000..ba383d5 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_var.h @@ -0,0 +1,434 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: scsp_var.h,v 1.5 1998/08/13 20:11:17 johnc Exp $ + * + */ + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP message formats + * + */ + +#ifndef _SCSP_SCSP_VAR_H +#define _SCSP_SCSP_VAR_H + + +/* + * Protocol constants + */ +#define SCSP_Open_Interval 30 +#define SCSP_HELLO_Interval 3 +#define SCSP_HELLO_DF 3 +#define SCSP_CAReXmitInterval 3 +#define SCSP_CSUSReXmitInterval 3 +#define SCSP_CSA_HOP_CNT 3 +#define SCSP_CSUReXmitInterval 2 +#define SCSP_CSUReXmitMax 5 + + +/* + * Operational constants + */ +#define SCSPD_CONFIG "/etc/scspd.conf" +#define SCSPD_DIR "/tmp" +#define SCSPD_DUMP "/tmp/scspd.dump" +#define SCSP_HASHSZ 19 +#define SCSPD_SOCK_NAME "SCSPD" + + +/* + * HELLO finite state machine states + */ +#define SCSP_HFSM_DOWN 0 +#define SCSP_HFSM_WAITING 1 +#define SCSP_HFSM_UNI_DIR 2 +#define SCSP_HFSM_BI_DIR 3 +#define SCSP_HFSM_STATE_CNT SCSP_HFSM_BI_DIR + 1 + + +/* + * HELLO finite state machine events + */ +#define SCSP_HFSM_VC_ESTAB 0 +#define SCSP_HFSM_VC_CLOSED 1 +#define SCSP_HFSM_HELLO_T 2 +#define SCSP_HFSM_RCV_T 3 +#define SCSP_HFSM_RCVD 4 +#define SCSP_HFSM_EVENT_CNT SCSP_HFSM_RCVD + 1 + + +/* + * Cache Alignment finite state machine states + */ +#define SCSP_CAFSM_DOWN 0 +#define SCSP_CAFSM_NEG 1 +#define SCSP_CAFSM_MASTER 2 +#define SCSP_CAFSM_SLAVE 3 +#define SCSP_CAFSM_UPDATE 4 +#define SCSP_CAFSM_ALIGNED 5 +#define SCSP_CAFSM_STATE_CNT SCSP_CAFSM_ALIGNED + 1 + + +/* + * Cache Alignment finite state machine events + */ +#define SCSP_CAFSM_HELLO_UP 0 +#define SCSP_CAFSM_HELLO_DOWN 1 +#define SCSP_CAFSM_CA_MSG 2 +#define SCSP_CAFSM_CSUS_MSG 3 +#define SCSP_CAFSM_CSU_REQ 4 +#define SCSP_CAFSM_CSU_REPLY 5 +#define SCSP_CAFSM_CA_T 6 +#define SCSP_CAFSM_CSUS_T 7 +#define SCSP_CAFSM_CSU_T 8 +#define SCSP_CAFSM_CACHE_UPD 9 +#define SCSP_CAFSM_CACHE_RSP 10 +#define SCSP_CAFSM_EVENT_CNT SCSP_CAFSM_CACHE_RSP + 1 + + +/* + * Client Interface finite state machine states + */ +#define SCSP_CIFSM_NULL 0 +#define SCSP_CIFSM_SUM 1 +#define SCSP_CIFSM_UPD 2 +#define SCSP_CIFSM_ALIGN 3 +#define SCSP_CIFSM_STATE_CNT SCSP_CIFSM_ALIGN + 1 + + +/* + * Client Interface finite state machine events + */ +#define SCSP_CIFSM_CA_DOWN 0 +#define SCSP_CIFSM_CA_SUMM 1 +#define SCSP_CIFSM_CA_UPD 2 +#define SCSP_CIFSM_CA_ALIGN 3 +#define SCSP_CIFSM_SOL_RSP 4 +#define SCSP_CIFSM_UPD_REQ 5 +#define SCSP_CIFSM_UPD_RSP 6 +#define SCSP_CIFSM_CSU_REQ 7 +#define SCSP_CIFSM_CSU_REPLY 8 +#define SCSP_CIFSM_CSU_SOL 9 +#define SCSP_CIFSM_EVENT_CNT SCSP_CIFSM_CSU_SOL + 1 + + +/* + * Server connection states (not part of any FSM) + */ +#define SCSP_SS_NULL 0 +#define SCSP_SS_CFG 1 +#define SCSP_SS_ACTIVE 2 + + +/* + * Hash a cache key + * + * key pointer to an Scsp_ckey structure + */ +#define SCSP_HASH(key) scsp_hash((key)) + + +/* + * Add a cache summary entry to a client's cache summary + * + * cpp pointer to a server control block + * key pointer to an Scsp_cse structure + */ +#define SCSP_ADD(cpp, key) \ +{ \ + Scsp_cse **c; \ + c = &(cpp)->ss_cache[SCSP_HASH(&(key)->sc_key)]; \ + LINK2TAIL((key), Scsp_cse, *c, sc_next); \ +} + + +/* + * Delete a cache summary entry from a client's cache summary + * + * cpp pointer to a server control block + * s pointer to an Scsp_cse structure + */ +#define SCSP_DELETE(cpp, s) \ +{ \ + Scsp_cse **c; \ + c = &(cpp)->ss_cache[SCSP_HASH(&(s)->sc_key)]; \ + UNLINK((s), Scsp_cse, *c, sc_next); \ +} + + +/* + * Search a client's cache summary for a given key + * + * cpp pointer to a server control block + * key pointer to an Scsp_ckey structure to find + * s Scsp_cse structure pointer to be set + */ +#define SCSP_LOOKUP(cpp, key, s) \ +{ \ + for ((s) = (cpp)->ss_cache[SCSP_HASH(key)]; \ + (s); \ + (s) = (s)->sc_next) { \ + if (scsp_cmp_key((key), &(s)->sc_key) == 0) \ + break; \ + } \ +} + + +/* + * SCSP pending connection control block + * + * The pending connection block is used to keep track of server + * connections which are open but haven't been identified yet. + */ +struct scsp_pending { + struct scsp_pending *sp_next; + int sp_sock; +}; +typedef struct scsp_pending Scsp_pending; + + +/* + * SCSP Server instance control block + */ +struct scsp_server { + struct scsp_server *ss_next; /* Server chain */ + char *ss_name; /* Server name */ + char ss_intf[IFNAMSIZ]; /* Interface */ + Atm_media ss_media; /* Physical comm medium */ + char ss_state; /* Server connection state */ + u_long ss_pid; /* Protocol ID */ + int ss_id_len; /* ID length */ + int ss_ckey_len; /* Cache key length */ + u_long ss_sgid; /* Server group ID */ + u_long ss_fid; /* Family ID */ + int ss_sock; /* Socket to client */ + int ss_dcs_lsock; /* DCS listen socket */ + Scsp_id ss_lsid; /* Local Server ID */ + Atm_addr ss_addr; /* Local ATM addr */ + Atm_addr ss_subaddr; /* Local ATM subaddr */ + int ss_mtu; /* Interface MTU */ + int ss_mark; + struct scsp_dcs *ss_dcs; /* Ptr to list of DCSs */ + struct scsp_cse *ss_cache[SCSP_HASHSZ]; /* Client's cache */ +}; +typedef struct scsp_server Scsp_server; + + +/* + * SCSP client cache summary entry control block + */ +struct scsp_cse { + struct scsp_cse *sc_next; /* Next on chain */ + long sc_seq; /* CSA sequence no */ + Scsp_ckey sc_key; /* Cache key */ + Scsp_id sc_oid; /* Origin ID */ +}; +typedef struct scsp_cse Scsp_cse; + + +/* + * CSU Request retransmission control block + */ +struct scsp_csu_rexmt { + struct scsp_csu_rexmt *sr_next; /* Next rexmit block */ + struct scsp_dcs *sr_dcs; /* DCS block */ + Scsp_csa *sr_csa; /* CSAs for rexmit */ + Harp_timer sr_t; /* Rexmit timer */ +}; +typedef struct scsp_csu_rexmt Scsp_csu_rexmt; + + +/* + * SCSP DCS control block + */ +struct scsp_dcs { + struct scsp_dcs *sd_next; /* DCS chain */ + Scsp_server *sd_server; /* Local server */ + Scsp_id sd_dcsid; /* DCS ID */ + Atm_addr sd_addr; /* DCS ATM address */ + Atm_addr sd_subaddr; /* DCS ATM subaddress */ + int sd_sock; /* Socket to DCS */ + Harp_timer sd_open_t; /* Open VCC retry timer */ + int sd_hello_state; /* Hello FSM state */ + int sd_hello_int; /* Hello interval */ + int sd_hello_df; /* Hello dead factor */ + int sd_hello_rcvd; /* Hello msg received */ + Harp_timer sd_hello_h_t; /* Hello timer */ + Harp_timer sd_hello_rcv_t; /* Hello receive timer */ + int sd_ca_state; /* CA FSM state */ + long sd_ca_seq; /* CA sequence number */ + int sd_ca_rexmt_int; /* CA rexmit interval */ + Scsp_msg *sd_ca_rexmt_msg; /* Saved CA msg */ + Scsp_cse *sd_ca_csas; /* CSAS still to send */ + Harp_timer sd_ca_rexmt_t; /* CA rexmit timer */ + int sd_csus_rexmt_int; /* CSUS rexmit int */ + Scsp_csa *sd_crl; /* Cache req list */ + Scsp_msg *sd_csus_rexmt_msg; /* Saved CSUS msg */ + Harp_timer sd_csus_rexmt_t; /* CSUS rexmit timer */ + int sd_hops; /* CSA hop count */ + Scsp_csa *sd_csu_ack_pend; /* CSUs to be ACKed */ + Scsp_csa *sd_csu_ack; /* CSUs ACKed */ + int sd_csu_rexmt_int; /* CSU Req rxmt time */ + int sd_csu_rexmt_max; /* CSU Req rxmt limit */ + Scsp_csu_rexmt *sd_csu_rexmt; /* CSU Req rxmt queue */ + int sd_client_state; /* Client I/F state */ +}; +typedef struct scsp_dcs Scsp_dcs; + +/* + * Trace options + */ +#define SCSP_TRACE_HFSM 1 /* Trace the Hello FSM */ +#define SCSP_TRACE_CAFSM 2 /* Trace the CA FSM */ +#define SCSP_TRACE_CFSM 4 /* Trace the server I/F FSM */ +#define SCSP_TRACE_HELLO_MSG 8 /* Trace Hello protocol msgs */ +#define SCSP_TRACE_CA_MSG 16 /* Trace CA protocol msgs */ +#define SCSP_TRACE_IF_MSG 32 /* Trace server I/F msgs */ + + +/* + * Global variables + */ +extern char *prog; +extern FILE *cfg_file; +extern int parse_line; +extern char *scsp_config_file; +extern FILE *scsp_log_file; +extern int scsp_log_syslog; +extern Scsp_server *scsp_server_head; +extern Scsp_pending *scsp_pending_head; +extern int scsp_max_socket; +extern int scsp_debug_mode; +extern int scsp_trace_mode; +extern FILE *scsp_trace_file; + + +/* + * Executable functions + */ +/* scsp_cafsm.c */ +extern int scsp_cafsm __P((Scsp_dcs *, int, void *)); + +/* scsp_config.c */ +extern int scsp_config __P((char *)); + +/* scsp_hfsm.c */ +extern int scsp_hfsm __P((Scsp_dcs *, int, Scsp_msg *)); + +/* scsp_if.c */ +extern int scsp_cfsm __P((Scsp_dcs *, int, Scsp_msg *, + Scsp_if_msg *)); + +/* scsp_input.c */ +extern void scsp_free_msg __P((Scsp_msg *)); +extern Scsp_msg *scsp_parse_msg __P((char *, int)); + +/* scsp_log.c */ +#if __STDC__ +extern void scsp_log __P((const int, const char *, ...)); +extern void scsp_trace __P((const char *, ...)); +#else +extern void scsp_log __P((int, char *, va_alist)); +extern void scsp_trace __P((const char *, va_alist)); +#endif +extern void scsp_open_trace __P(()); +extern void scsp_trace_msg __P((Scsp_dcs *, Scsp_msg *, int)); +extern void scsp_mem_err __P((char *)); + +/* scsp_msg.c */ +extern void scsp_csus_ack __P((Scsp_dcs *, Scsp_msg *)); +extern int scsp_send_ca __P((Scsp_dcs *)); +extern int scsp_send_csus __P((Scsp_dcs *)); +extern int scsp_send_csu_req __P((Scsp_dcs *, Scsp_csa *)); +extern int scsp_send_csu_reply __P((Scsp_dcs *, Scsp_csa *)); +extern int scsp_send_hello __P((Scsp_dcs *)); + +/* scsp_output.c */ +extern int scsp_format_msg __P((Scsp_dcs *, Scsp_msg *, char **)); +extern int scsp_send_msg __P((Scsp_dcs *, Scsp_msg *)); + +/* scsp_print.c */ +extern char *format_hfsm_state __P((int)); +extern char *format_hfsm_event __P((int)); +extern char *format_cafsm_state __P((int)); +extern char *format_cafsm_event __P((int)); +extern char *format_cifsm_state __P((int)); +extern char *format_cifsm_event __P((int)); +extern void print_scsp_cse __P((FILE *, Scsp_cse *)); +extern void print_scsp_msg __P((FILE *, Scsp_msg *)); +extern void print_scsp_if_msg __P((FILE *, Scsp_if_msg *)); +extern void print_scsp_pending __P((FILE *, Scsp_pending *)); +extern void print_scsp_server __P((FILE *, Scsp_server *)); +extern void print_scsp_dcs __P((FILE *, Scsp_dcs *)); +extern void print_scsp_dump __P(()); + +/* scsp_socket.c */ +extern Scsp_dcs * scsp_find_dcs __P((int)); +extern Scsp_server * scsp_find_server __P((int)); +extern int scsp_dcs_connect __P((Scsp_dcs *)); +extern int scsp_dcs_listen __P((Scsp_server *)); +extern Scsp_dcs * scsp_dcs_accept __P((Scsp_server *)); +extern int scsp_dcs_read __P((Scsp_dcs *)); +extern int scsp_server_listen __P(()); +extern int scsp_server_accept __P((int)); +extern Scsp_if_msg * scsp_if_sock_read __P((int)); +extern int scsp_server_read __P((Scsp_server *)); +extern int scsp_pending_read __P((Scsp_pending *)); + +/* scsp_subr.c */ +extern int scsp_hash __P((Scsp_ckey *)); +extern int scsp_cmp_id __P((Scsp_id *, Scsp_id *)); +extern int scsp_cmp_key __P((Scsp_ckey *, Scsp_ckey *)); +extern int scsp_is_atmarp_server __P((char *)); +extern Scsp_cse * scsp_dup_cse __P((Scsp_cse *)); +extern Scsp_csa * scsp_dup_csa __P((Scsp_csa *)); +extern Scsp_csa * scsp_cse2csas __P((Scsp_cse *)); +extern void scsp_dcs_cleanup __P((Scsp_dcs *)); +extern void scsp_dcs_delete __P((Scsp_dcs *)); +extern void scsp_server_shutdown __P((Scsp_server *)); +extern void scsp_server_delete __P((Scsp_server *)); +extern int scsp_get_server_info __P((Scsp_server *)); +extern void scsp_process_ca __P((Scsp_dcs *, Scsp_ca *)); +extern int scsp_propagate_csa __P(( Scsp_dcs *, + Scsp_csa *)); +extern void scsp_update_cache __P(( Scsp_dcs *, + Scsp_csa *)); +extern void scsp_reconfigure __P(()); + +/* scsp_timer.c */ +extern void scsp_open_timeout __P((Harp_timer *)); +extern void scsp_hello_timeout __P((Harp_timer *)); +extern void scsp_hello_rcv_timeout __P((Harp_timer *)); +extern void scsp_ca_retran_timeout __P((Harp_timer *)); +extern void scsp_csus_retran_timeout __P((Harp_timer *)); +extern void scsp_csu_req_retran_timeout __P((Harp_timer *)); + + + +#endif /* _SCSP_SCSP_VAR_H */ diff --git a/usr.sbin/atm/scspd/scspd.8 b/usr.sbin/atm/scspd/scspd.8 new file mode 100644 index 0000000..1a9b0ab --- /dev/null +++ b/usr.sbin/atm/scspd/scspd.8 @@ -0,0 +1,443 @@ +.\" +.\" =================================== +.\" 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. +.\" +.\" @(#) $Id: scspd.1,v 1.2 1998/08/26 21:39:38 johnc Exp $ +.\" +.\" +.de EX \"Begin example +.ne 5 +.if n .sp 1 +.if t .sp .5 +.nf +.in +.5i +.. +.de EE +.fi +.in -.5i +.if n .sp 1 +.if t .sp .5 +.. +.TH SCSPD 8 "1998-08-21" "HARP" + +.SH NAME +scspd \- SCSP daemon +.SH SYNOPSIS +.B scspd +[\fB-f\fP <cfg-file>] +[\fB-d\fP] +[\fB-T\fP<options>] + +.SH DESCRIPTION +\fIScspd\fP is an implementation of the Server Cache Synchronization +Protocol (SCSP) for the Host ATM Research Platform (HARP) +networking software. +\fIScspd\fP synchronizes the cache(s) of server(s) +running on a host with the caches of servers on remote hosts. +SCSP is defined for a number of different protocols, but the present +version of \fIscspd\fP only supports ATMARP. +.PP +By using \fIscspd\fP and \fIatmarpd\fP, one can provide multiple +ATMARP servers in a single ATM LIS. +This might be useful, for example, when a LIS consists of a number of +local-area ATM networks connected by long-distance links. +Each local-area network could have its own ATMARP server, with all the +servers' caches being synchronized by SCSP. +Then, if a long-distance link fails, hosts on a local-area network +will still have connectivity to other local hosts (since they all use +the local ATMARP server); when the long-distance link is restored, +SCSP will re-synchronize the servers' caches, restoring +connectivity to remote hosts. +Both \fIscspd\fP and \fIatmarpd\fP must be running before any ATMARP +cache synchronization can take place. +.PP +\fIScspd\fP implements SCSP as specified in RFC 2334, \fIServer Cache +Synchronization Protocol (SCSP)\fP and +draft-ietf-ion-scspd-atmarpd-00.txt, \fIA Distributed ATMARP Service +using SCSP\fP. + +When \fIscspd\fP starts, it parses its command line and puts +itself into the background. + +.SH TERMINOLOGY +Some of the vocabulary associated with SCSP can be confusing. +In this document, the following definitions are used: + +\fBClient server\fP or \fBlocal server\fP means the server running on +the same host as \fIscspd\fP whose cache is to be synchronized with that +of one or more remote servers. +When the word \fBserver\fP is used alone, it means "client server". + +\fBRemote server\fP means a server running on some host other than +the one where \fIscspd\fP is running. + +\fBDirectly Connected Server\fP (DCS) means a remote server that +\fIscspd\fP communicates with directly. +The remote server will also be running an implementation of SCSP. + +\fBCache Alignment\fP (CA) has two meanings. +The Cache Alignment protocol is a part of the SCSP protocol +specification, and the Cache Alignment finite state machine (FSM) +is a finite state machine that implements the Cache Alignment +protocol. + +.SH OPTIONS +The command-line options are: +.IP "\fB-f\fP <cfg-file>" 15 +Specifies the name of the configuration file. +If this option is not specified, \fIscspd\fP looks for the +file /etc/scspd.conf. +.IP "\fB-d\fP" 15 +Specifies that \fIscspd\fP is to be run in debug mode. +In debug mode, the daemon is not put into the background. +Log messages are written to standard output instead of to +the log file specified in the configuration file. +.IP "\fB-T\fP<options>" 15 +Specifies that \fIscspd\fP will trace specified events and messages +as it executes. +The \fB-T\fP flag is followed by one or more of the following +options: +.in +4 +.ti -4 +\fBc\fP\ -\ trace \fIscspd\fP's CA Finite State Machine (FSM), +.ti -4 +\fBh\fP\ -\ trace \fIscspd\fP's Hello FSM, +.ti -4 +\fBi\fP\ -\ trace \fIscspd\fP's Client Interface FSM, +.ti -4 +\fBC\fP\ -\ trace CA, CSUS, CSU Request, and CSU Reply messages, +.ti -4 +\fBH\fP\ -\ trace Hello messages, +.ti -4 +\fBI\fP\ -\ trace interface messages to and from \fIscspd\fP's +clients. +.in -4 +.SH CONFIGURATION + +The configuration file consists of a sequence of configuration +statements. +These statements specify information about the servers, +both local and remote, whose +caches are to be synchronized by \fIscspd\fP. +RFC 2334, \fIServer Cache +Synchronization Protocol (SCSP)\fP and +draft-ietf-ion-scspd-atmarpd-00.txt, \fIA Distributed ATMARP Service +using SCSP\fP +will be valuable in understanding how to configure \fIscspd\fP. + +A configuration statement other than a comment is terminated by a +semicolon. +Some statements contain blocks, delimited by braces ("{" and "}"). +Configuration statement keywords are not case-sensitive, +but some parameters (e.g. interface names) are. +Configuration statments can span multiple lines. + +.SS Comments +Three types of comments are allowed: + +\fB# comments\fP: +any characters from "#" to the end of the line are ignored. + +\fBC comments\fP: +any characters between "/*" and "*/" are ignored. + +\fBC++ comments\fP: +any characters from "//" to the end of the line are ignored. + +.SS "Statements" +The configuration statements recognized by \fIscspd\fP are: + +Server <name> { +.in +5 +Protocol <protocol ID>; +.br +Netif <if_name>; +.br +ServerGroupID <ID>; +.br +FamilyID <ID>; +.br +DCS { +.in +5 +ATMaddr <ATM address>; +.br +ID <host>; +.br +CAReXmitInt <int>; +.br +CSUSReXmitInt <int>; +.br +CSUReXmitInt <int>; +.br +CSUReXmitMax <cnt>; +.br +HelloDead <cnt>; +.br +HelloInt <int>; +.br +Hops <cnt>; +.in -5 +}; +.in -5 +}; +.sp +Log { +.in +5 +File <file name>; +.br +Syslog; +.in -5 +}; +.PP +Where a host address needs to be specified in the configuration file, +either a DNS name or an IP address in dotted decimal format can +be used. +.PP +ATM addresses are specified as strings of hex digits, with an +optional leading "0x". +Fields within the address may be separated by periods, but periods +are for readability only and are ignored. +ATM addresses are 20 bytes long. +The full address, including any leading zeroes, must be given. +For example: +.in +5 +0x47.0005.80.ffe100.0000.f21a.0170.0020481a0170.00 +.in -5 + +.SS "Server Statement" +The \fBserver\fP statement specifies a client server whose cache +to be synchronized with the caches of other servers +running on remote hosts. +There will be one \fBserver\fP statement in the configuration file +for each client server whose cache is to be synchronized by \fIscspd\fP. +The format of the \fBserver\fP statement is: +.ti +5 +\fBServer <name> { <statements> };\fP + +A name must be specified on the \fBserver\fP statement, but it is +not used by \fIscspd\fP. +It is expected to give a brief description of the server's purpose. + +The \fBserver\fP statement has several sub-statements +that specify the details of the \fIscspd\fP's configuration. +They are: +.IP "\fBProtocol ATMARP;\fP" 5 +The only protocol supported by the current version of \fIscspd\fP +is ATMARP. +The \fBprotocol\fP statement must always be specified. +.IP "\fBNetif <intf>;\fP" 5 +The \fBnetif\fP statement specifies the name of the ATM network +interface on which a client server is providing service. +The \fBnetif\fP statement must always be specified. +.IP "\fBServerGroupID <ID>;\fP" 5 +The \fBServerGroupID\fP statement specifies an identifier for the +group of servers being synchronized by \fIscspd\fP. +The ID is specified as a decimal number in the range 0 - 65,535. +The server group ID must be the same for all servers whose caches +are being synchronized by an SCSP session. +That is, the server group ID for a host must be the same for all +Directly Connected Servers (DCSs) pointed to within a +\fBserver\fP statement. +The \fBServerGroupID\fP statement must always be specified. +.IP "\fBFamilyID <ID>;\fP" 5 +The \fBfamilyID\fP statement specifies an identifier for a family +of parallel SCSP sessions running between a group of hosts (i.e. a +set of SCSP sessions with different protocol IDs but the same set +of servers). +The ID is specified as a decimal number in the range 0 - 65,535. +The family ID is currently not used by \fIscspd\fP. + +.SS "DCS Statement" +The \fBDCS\fP statement is a sub-statement of the \fBserver\fP statement +that specifies the characteristics of a Directly Connected Server (DCS). +The \fBserver\fP statement will have one \fBDCS\fP statement for +each DCS that \fIscspd\fP is to exchange information with. +The \fBDCS\fP statement has a number of sub-statements that specify the +details of the configuration for the DCS. They are: +.IP "\fBATMaddr <ATM address>;\fP" 5 +The \fBATMaddr\fP statement specifies the ATM address of the DCS. +The \fBATMaddr\fP statement must always be specified. +.IP "\fBID <host>;\fP" 5 +The \fBID\fP statement specifies the SCSP identifier of the DCS. +For ATMARP, the ID is the IP address or DNS name associated with the +ATM interface of the DCS. +The \fBID\fP statement must always be specified. +.IP "\fBCAReXmitInt <int>;\fP" 5 +The \fBCAReXmitInt\fP statement specifies the interval that is +allowed to elapse between retransmissions of CA messages. +If a CA message is sent and an acknowledgement is not received within +CAReXmitInt seconds, the message will be retransmitted. +The default value for \fBCAReXmitInt\fP is 3 seconds. +.IP "\fBCSUSReXmitInt <int>;\fP" 5 +The \fBCSUSReXmitInt\fP statement specifies the interval that is +allowed to elapse between retransmissions of CSU Solicit messages. +When a CSUS message is sent, any Cache State Advertisements (CSAs) +requested by the CSUS that have +not been received within CSUSReXmitInt seconds will be requested +again by another CSUS message. +The default value for \fBCSUSReXmitInt\fP is 3 seconds. +Be careful not to confuse \fBCSUSReXmitInt\fP and \fBCSUReXmitInt\fP. +.IP "\fBCSUReXmitInt <int>;\fP" 5 +The \fBCSUReXmitInt\fP statement specifies the interval that is +allowed to elapse between retransmissions of CSU Request messages. +When a CSU Request message is sent, any CSAs that are not acknowledged +by a CSU Reply message within CSUReXmitInt seconds will +be retransmitted. +The default value for \fBCSUReXmitInt\fP is 2 seconds. +Be careful not to confuse \fBCSUReXmitInt\fP and \fBCSUSReXmitInt\fP. +.IP "\fBCSUReXmitMax <cnt>;\fP" 5 +The \fBCSUReXmitMax\fP statement specifies the number of times that +a CSA will be retransmitted as described above before SCSP gives up +on the CSA and discards it. +The default value for \fBCSUReXmitMax\fP is 5. +.IP "\fBHelloDead <cnt>;\fP" 5 +The \fBHelloDead\fP statement specifies the Hello Dead Factor that +will be sent to the DCS in Hello messages. +A "DCS down" condition will be detected when nothing is received from +a DCS in HelloDead * HelloInt seconds. +The default value for \fBHelloDead\fP is 3. +.IP "\fBHelloInt <int>;\fP" 5 +The \fBHelloInt\fP statement specifies the Hello Interval that +will be sent to the DCS in Hello messages. +The default value for \fBHelloInt\fP is 3 seconds. +.IP "\fBHops <cnt>;\fP" 5 +The \fBHops\fP statement specifies the number of hops (DCS to DCS) +that will be specified in CSAs originating from the local server. +This number must be at least as large as the diameter of the +server group. +That is, it must be large enough for a CSA to be propagated from +server to server all the way across the server group. +The default value for \fBHops\fP is 3. + +.SS "Log Statement" +The \fBlog\fP statement specifies how \fIscspd\fP is to log +information about its operation. +\fIScspd\fP can write log information to a file, to the system log, +or both. +.IP "\fBFile <file name>;\fP" 5 +The \fBfile\fP statement specifies that \fIscspd\fP is to write +its log messages to the named file. +Log messages will be appended to the end of the file if +it already exists. +.IP "\fBSyslog;\fP" 5 +The \fBsyslog\fP statement specifies that \fIscspd\fP is to write +its log messages to the syslog facility. +\fIScspd\fP writes its messages to syslog with a facility code +of LOG_DAEMON. + +.in -5 +If no \fBlog\fP statement is specified, \fIscspd\fP writes log +messages to the system log. +If both \fBfile\fP and \fBsyslog\fP are specified, \fIscspd\fP will +write log messages to both the named file and the system log. + +.SS Examples + +An example of a simple configuration file for \fIscspd\fP might be: +.in +5 +server atmarp_ni0 { +.in +5 +protocol ATMARP; +.br +netif ni0; +.br +ServerGroupID 23; +.br +DCS { +.in +5 +.br +ID 10.1.1.2; +.br +ATMaddr 0x47.0005.80.ffdc00.0000.0002.0001.002048061de7.00; +.br +hops 2; +.in -5 +}; +.in -5 +}; +.in -5 + +This configuration would synchronize the cache of the ATMARP server +operating on network interface ni0 with the cache of a second server +running on a host whose IP address is 10.1.1.2. +Log messages would be written to the system log. + + +.SH SIGNAL PROCESSING +The following signals can be used to control \fIscspd\fP: + +.IP \fBSIGHUP\fP 10 +Reread the configuration file and restart \fIscspd\fP. + +.IP \fBSIGINT\fP 10 +Dump debugging information to a file. +When it receives a SIGINT signal, \fIscspd\fP dumps a summary of +its control blocks to a text file (see "\fBFILES\fP"). + +.SH FILES + +.IP "/etc/scspd.conf" +\fIScspd\fP default configuration file name. +A different file name can be specified with the \fB-f\fP command-line +option. + +.IP "/tmp/scspd.<pid>.<seq>.out" +Debugging information dump file name. +\fIScspd\fP writes a summary of its control blocks to this file +when it receives a SIGINT signal. +<pid> is the process ID of the daemon and <seq> is a sequence +number which is incremented every time a dump is taken. + +.IP "/tmp/scspd.<pid>.trace" +Trace file. +\fIScspd\fP writes trace information to this file if the \fB-T\fP +option is specified on the command line. + +.SH "SEE ALSO" +\fIatm\fP (8); +\fIatmarpd\fP (8); +RFC 2334, \fIServer Cache Synchronization Protocol (SCSP)\fP; +draft-ietf-ion-scsp-atmarpd-00.txt, \fIA Distributed ATMARP Service +Using SCSP\fP. + + +.SH BUGS +If \fIscspd\fP terminates and is restarted, there will be a period of +instability while previously-synchronized cache entries time out and are +refreshed. + +Please report any bugs to harp-bugs@magic.net. + +.SH COPYRIGHT +Copyright (c) 1994-1998, Network Computing Services, Inc. + +.SH AUTHORS +John Cavanaugh, Network Computing Services, Inc. +.br +Mike Spengler, Network Computing Services, Inc. +.br +Joe Thomas, Network Computing Services, Inc. +.fi +.SH ACKNOWLEDGMENTS +This software was developed with the support of the Defense +Advanced Research Projects Agency (DARPA). diff --git a/usr.sbin/atm/scspd/scspd.c b/usr.sbin/atm/scspd/scspd.c new file mode 100644 index 0000000..74fe868 --- /dev/null +++ b/usr.sbin/atm/scspd/scspd.c @@ -0,0 +1,545 @@ +/* + * + * =================================== + * 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. + * + * @(#) $Id: scspd.c,v 1.6 1998/08/21 18:08:25 johnc Exp $ + * + */ + + +/* + * Server Cache Synchronization Protocol (SCSP) Support + * ---------------------------------------------------- + * + * SCSP server daemon main line code + * + */ + + +#ifndef lint +static char *RCSid = "@(#) $Id: scspd.c,v 1.6 1998/08/21 18:08:25 johnc Exp $"; +#endif + +#include <sys/types.h> +#include <sys/param.h> + +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <sys/socket.h> +#include <net/if.h> +#include <netinet/in.h> +#include <sys/ttycom.h> +#include <netatm/queue.h> +#include <netatm/atm.h> +#include <netatm/atm_if.h> +#include <netatm/atm_sap.h> +#include <netatm/atm_sys.h> +#include <netatm/atm_ioctl.h> + +#include <libatm.h> +#include "scsp_msg.h" +#include "scsp_if.h" +#include "scsp_var.h" + + +/* + * Global variables + */ +char *prog; +char *scsp_config_file = SCSPD_CONFIG; +FILE *scsp_log_file = (FILE *)0; +int scsp_log_syslog = 0; +Scsp_server *scsp_server_head = (Scsp_server *)0; +Scsp_pending *scsp_pending_head = (Scsp_pending *)0; +int scsp_max_socket = -1; +int scsp_debug_mode = 0; +int scsp_trace_mode = 0; + + +/* + * Local variables + */ +static int scsp_hup_signal = 0; +static int scsp_int_signal = 0; + + +/* + * SIGHUP signal handler + * + * Arguments: + * sig signal number + * + * Returns: + * none + * + */ +void +scsp_sighup(sig) + int sig; +{ + /* + * Flag the signal + */ + scsp_hup_signal = 1; +} + + +/* + * SIGINT signal handler + * + * Arguments: + * sig signal number + * + * Returns: + * none + * + */ +void +scsp_sigint(sig) + int sig; +{ + /* + * Flag the signal + */ + scsp_int_signal = 1; +} + + +/* + * Process command line parameters + * + * Arguments: + * argc number of command-line arguments + * argv list of pointers to command-line arguments + * + * Returns: + * none + * + */ +void +initialize(argc, argv) + int argc; + char **argv; +{ + int i; + char *cp; + + /* + * Save program name, ignoring any path components + */ + if (prog = (char *)strrchr(argv[0], '/')) + prog++; + else + prog = argv[0]; + + /* + * Make sure we're being invoked by the super user + */ + i = getuid(); + if (i != 0) { + fprintf(stderr, "%s: You must be root to run this program\n", + prog); + exit(1); + } + + /* + * Check for command-line options + */ + for (i = 1; i < argc; i++) { + if (strcmp(argv[i], "-d") == 0) { + /* + * -d option -- set debug mode + */ + scsp_debug_mode = 1; + } else if (strcmp(argv[i], "-f") == 0) { + /* + * -f option -- set config file name + */ + i++; + if (i >= argc) { + fprintf(stderr, "%s: Configuration file name missing\n", + prog); + exit(1); + } + scsp_config_file = argv[i]; + } else if (strncmp(argv[i], "-T", 2) == 0) { + /* + * -T option -- trace options + */ + for (cp = &argv[i][2]; *cp; cp++) { + if (*cp == 'c') + scsp_trace_mode |= SCSP_TRACE_CAFSM; + else if (*cp == 'h') + scsp_trace_mode |= SCSP_TRACE_HFSM; + else if (*cp == 'i') + scsp_trace_mode |= SCSP_TRACE_CFSM; + else if (*cp == 'C') + scsp_trace_mode |= SCSP_TRACE_CA_MSG; + else if (*cp == 'H') + scsp_trace_mode |= SCSP_TRACE_HELLO_MSG; + else if (*cp == 'I') + scsp_trace_mode |= SCSP_TRACE_IF_MSG; + else + fprintf(stderr, "Invalid trace specification '%c' ignored\n", + *cp); + } + } else { + /* + * Error -- unrecognized option + */ + fprintf(stderr, "%s: Unrecognized option \"%s\"\n", + prog, argv[i]); + exit(1); + } + } +} + + +/* + * Daemon housekeeping + * + * Arguments: + * None + * + * Returns: + * None + * + */ +static void +start_daemon() + +{ + int dpid, fd, file_count, rc; + + /* + * Ignore selected signals + */ +#ifdef SIGTTOU + signal(SIGTTOU, SIG_IGN); +#endif +#ifdef SIGTTIN + signal(SIGTTIN, SIG_IGN); +#endif +#ifdef SIGTSTP + signal(SIGTSTP, SIG_IGN); +#endif +#ifdef SIGPIPE + signal(SIGPIPE, SIG_IGN); +#endif + + + /* + * Don't put the daemon into the background if + * we're in debug mode + */ + if (scsp_debug_mode) + goto daemon_bypass; + + /* + * Put the daemon into the background + */ + dpid = fork(); + if (dpid < 0) { + scsp_log(LOG_ERR, "fork failed"); + abort(); + } + if (dpid > 0) { + /* + * This is the parent process--just exit and let + * the daughter do all the work + */ + exit(0); + } + + /* + * Disassociate from any controlling terminal + */ + rc = setpgrp(0, getpid()); + if (rc <0) { + scsp_log(LOG_ERR, "can't change process group"); + exit(1); + } + fd = open("/dev/tty", O_RDWR); + if (fd >= 0) { + ioctl(fd, TIOCNOTTY, (char *)0); + close(fd); + } + + /* + * Close all open file descriptors + */ + file_count = getdtablesize(); + for (fd=0; fd<file_count; fd++) { + close(fd); + } + + /* + * Set up timers + */ +daemon_bypass: + init_timer(); + + /* + * Move to a safe directory + */ + chdir(SCSPD_DIR); + + /* + * Clear the file mode creation mask + */ + umask(0); + + + /* + * Set up signal handlers + */ + rc = (int)signal(SIGHUP, scsp_sighup); + if (rc == -1) { + scsp_log(LOG_ERR, "SIGHUP signal setup failed"); + exit(1); + } + + rc = (int)signal(SIGINT, scsp_sigint); + if (rc == -1) { + scsp_log(LOG_ERR, "SIGINT signal setup failed"); + exit(1); + } + + /* + * Set up syslog for error logging + */ + if (scsp_log_syslog || !scsp_log_file) { + openlog(prog, LOG_PID | LOG_CONS, LOG_DAEMON); + } + scsp_log(LOG_INFO, "Starting SCSP daemon"); +} + + +/* + * Main line code + * + * Process command line parameters, read configuration file, connect + * to configured clients, process data from DCSs. + * + * Arguments: + * argc number of command-line arguments + * argv list of pointers to command-line arguments + * + * Returns: + * none + * + */ +main(argc, argv) + int argc; + char *argv[]; + +{ + int i, rc, scsp_server_lsock; + Scsp_server *ssp; + Scsp_dcs *dcsp; + Scsp_pending *next_psp, *psp; + fd_set read_set, write_set, except_set; + + /* + * Process command line arguments + */ + initialize(argc, argv); + + /* + * Put the daemon into the background + */ + start_daemon(); + + /* + * Process configuration file + */ + rc = scsp_config(scsp_config_file); + if (rc) { + scsp_log(LOG_ERR, "Found %d error%s in configuration file", + rc, ((rc == 1) ? "" : "s")); + exit(1); + } + + /* + * Open the trace file if we need one + */ + if (scsp_trace_mode) { + scsp_open_trace(); + } + + /* + * Listen for connections from clients + */ + scsp_server_lsock = scsp_server_listen(); + if (scsp_server_lsock == -1) { + scsp_log(LOG_ERR, "server listen failed"); + abort(); + } + + /* + * Main program loop -- we wait for: + * a server listen to complete + * a DCS listen to complete + * a DCS connect to complete + * data from a server + * data from a DCS + */ + while (1) { + /* + * Set up the file descriptor sets and select to wait + * for input + */ + FD_ZERO(&read_set); + FD_ZERO(&write_set); + FD_ZERO(&except_set); + FD_SET(scsp_server_lsock, &read_set); + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + if (ssp->ss_dcs_lsock != -1) + FD_SET(ssp->ss_dcs_lsock, &read_set); + if (ssp->ss_sock != -1) + FD_SET(ssp->ss_sock, &read_set); + for (dcsp = ssp->ss_dcs; dcsp; + dcsp = dcsp->sd_next) { + if (dcsp->sd_sock != -1) { + if (dcsp->sd_hello_state == + SCSP_HFSM_DOWN ) + FD_SET(dcsp->sd_sock, + &write_set); + else + FD_SET(dcsp->sd_sock, + &read_set); + } + } + } + for (psp = scsp_pending_head; psp; psp = psp->sp_next) { + FD_SET(psp->sp_sock, &read_set); + } + rc = select(scsp_max_socket + 1, &read_set, + &write_set, &except_set, + (struct timeval *)0); + if (rc < 0) { + /* + * Select error--check for possible signals + */ + if (harp_timer_exec) { + /* + * Timer tick--process it + */ + timer_proc(); + continue; + } else if (scsp_hup_signal) { + /* + * SIGHUP signal--reconfigure + */ + scsp_hup_signal = 0; + scsp_reconfigure(); + continue; + } else if (scsp_int_signal) { + /* + * SIGINT signal--dump control blocks + */ + print_scsp_dump(); + scsp_int_signal = 0; + continue; + } else if (errno == EINTR) { + /* + * EINTR--just ignore it + */ + continue; + } else { + /* + * Other error--this is a problem + */ + scsp_log(LOG_ERR, "Select failed"); + abort(); + } + } + + /* + * Check the read set for connections from servers + */ + if (FD_ISSET(scsp_server_lsock, &read_set)) { + FD_CLR(scsp_server_lsock, &read_set); + rc = scsp_server_accept(scsp_server_lsock); + } + + /* + * Check the write set for new connections to DCSs + */ + for (i = 0; i <= scsp_max_socket; i++) { + if (FD_ISSET(i, &write_set)) { + FD_CLR(i, &write_set); + if (dcsp = scsp_find_dcs(i)) { + rc = scsp_hfsm(dcsp, + SCSP_HFSM_VC_ESTAB, + (Scsp_msg *)0); + } + } + } + + /* + * Check the read set for connections from DCSs + */ + for (ssp = scsp_server_head; ssp; ssp = ssp->ss_next) { + if (ssp->ss_dcs_lsock != -1 && + FD_ISSET(ssp->ss_dcs_lsock, + &read_set)) { + FD_CLR(ssp->ss_dcs_lsock, &read_set); + dcsp = scsp_dcs_accept(ssp); + if (dcsp) { + rc = scsp_hfsm(dcsp, + SCSP_HFSM_VC_ESTAB, + (Scsp_msg *)0); + } + } + } + + /* + * Check the read set for data from pending servers + */ + for (psp = scsp_pending_head; psp; psp = next_psp) { + next_psp = psp->sp_next; + if (FD_ISSET(psp->sp_sock, &read_set)) { + FD_CLR(psp->sp_sock, &read_set); + rc = scsp_pending_read(psp); + } + } + + /* + * Check the read set for data from servers or DCSs + */ + for (i = 0; i <= scsp_max_socket; i++) { + if (FD_ISSET(i, &read_set)) { + if (ssp = scsp_find_server(i)) { + rc = scsp_server_read(ssp); + } else if (dcsp = scsp_find_dcs(i)) { + rc = scsp_dcs_read(dcsp); + } + } + } + } +} |