summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/hea/eni.c664
-rw-r--r--sys/dev/hea/eni.h499
-rw-r--r--sys/dev/hea/eni_buffer.c465
-rw-r--r--sys/dev/hea/eni_globals.c102
-rw-r--r--sys/dev/hea/eni_if.c270
-rw-r--r--sys/dev/hea/eni_init.c142
-rw-r--r--sys/dev/hea/eni_intr.c230
-rw-r--r--sys/dev/hea/eni_receive.c871
-rw-r--r--sys/dev/hea/eni_stats.h134
-rw-r--r--sys/dev/hea/eni_suni.h78
-rw-r--r--sys/dev/hea/eni_transmit.c823
-rw-r--r--sys/dev/hea/eni_var.h85
-rw-r--r--sys/dev/hea/eni_vcm.c283
-rw-r--r--sys/dev/hfa/fore.h144
-rw-r--r--sys/dev/hfa/fore_aali.h604
-rw-r--r--sys/dev/hfa/fore_buffer.c772
-rw-r--r--sys/dev/hfa/fore_command.c445
-rw-r--r--sys/dev/hfa/fore_globals.c119
-rw-r--r--sys/dev/hfa/fore_if.c205
-rw-r--r--sys/dev/hfa/fore_include.h139
-rw-r--r--sys/dev/hfa/fore_init.c314
-rw-r--r--sys/dev/hfa/fore_intr.c268
-rw-r--r--sys/dev/hfa/fore_load.c1618
-rw-r--r--sys/dev/hfa/fore_output.c415
-rw-r--r--sys/dev/hfa/fore_receive.c582
-rw-r--r--sys/dev/hfa/fore_slave.h191
-rw-r--r--sys/dev/hfa/fore_stats.c164
-rw-r--r--sys/dev/hfa/fore_stats.h83
-rw-r--r--sys/dev/hfa/fore_timer.c97
-rw-r--r--sys/dev/hfa/fore_transmit.c371
-rw-r--r--sys/dev/hfa/fore_var.h269
-rw-r--r--sys/dev/hfa/fore_vcm.c321
-rw-r--r--sys/netatm/atm.h651
-rw-r--r--sys/netatm/atm_aal5.c905
-rw-r--r--sys/netatm/atm_cm.c3464
-rw-r--r--sys/netatm/atm_cm.h348
-rw-r--r--sys/netatm/atm_device.c883
-rw-r--r--sys/netatm/atm_if.c1202
-rw-r--r--sys/netatm/atm_if.h392
-rw-r--r--sys/netatm/atm_ioctl.h432
-rw-r--r--sys/netatm/atm_pcb.h92
-rw-r--r--sys/netatm/atm_proto.c205
-rw-r--r--sys/netatm/atm_sap.h81
-rw-r--r--sys/netatm/atm_sigmgr.h109
-rw-r--r--sys/netatm/atm_signal.c512
-rw-r--r--sys/netatm/atm_socket.c1311
-rw-r--r--sys/netatm/atm_stack.h287
-rw-r--r--sys/netatm/atm_subr.c970
-rw-r--r--sys/netatm/atm_sys.h275
-rw-r--r--sys/netatm/atm_usrreq.c711
-rw-r--r--sys/netatm/atm_var.h208
-rw-r--r--sys/netatm/atm_vc.h89
-rw-r--r--sys/netatm/ipatm/ipatm.h55
-rw-r--r--sys/netatm/ipatm/ipatm_event.c454
-rw-r--r--sys/netatm/ipatm/ipatm_if.c335
-rw-r--r--sys/netatm/ipatm/ipatm_input.c210
-rw-r--r--sys/netatm/ipatm/ipatm_load.c878
-rw-r--r--sys/netatm/ipatm/ipatm_output.c216
-rw-r--r--sys/netatm/ipatm/ipatm_serv.h114
-rw-r--r--sys/netatm/ipatm/ipatm_usrreq.c394
-rw-r--r--sys/netatm/ipatm/ipatm_var.h215
-rw-r--r--sys/netatm/ipatm/ipatm_vcm.c1245
-rw-r--r--sys/netatm/kern_include.h112
-rw-r--r--sys/netatm/port.h564
-rw-r--r--sys/netatm/queue.h213
-rw-r--r--sys/netatm/sigpvc/sigpvc.h47
-rw-r--r--sys/netatm/sigpvc/sigpvc_if.c953
-rw-r--r--sys/netatm/sigpvc/sigpvc_subr.c181
-rw-r--r--sys/netatm/sigpvc/sigpvc_var.h95
-rw-r--r--sys/netatm/spans/spans_arp.c1133
-rw-r--r--sys/netatm/spans/spans_cls.c848
-rw-r--r--sys/netatm/spans/spans_cls.h188
-rw-r--r--sys/netatm/spans/spans_if.c1336
-rw-r--r--sys/netatm/spans/spans_kxdr.c684
-rw-r--r--sys/netatm/spans/spans_msg.c1633
-rw-r--r--sys/netatm/spans/spans_print.c1062
-rw-r--r--sys/netatm/spans/spans_proto.c558
-rw-r--r--sys/netatm/spans/spans_subr.c494
-rw-r--r--sys/netatm/spans/spans_util.c477
-rw-r--r--sys/netatm/spans/spans_var.h259
-rw-r--r--sys/netatm/spans/spans_xdr.x513
-rw-r--r--sys/netatm/uni/Makefile93
-rw-r--r--sys/netatm/uni/q2110_sigaa.c516
-rw-r--r--sys/netatm/uni/q2110_sigcpcs.c1760
-rw-r--r--sys/netatm/uni/q2110_subr.c239
-rw-r--r--sys/netatm/uni/qsaal1_sigaa.c518
-rw-r--r--sys/netatm/uni/qsaal1_sigcpcs.c1545
-rw-r--r--sys/netatm/uni/qsaal1_subr.c206
-rw-r--r--sys/netatm/uni/sscf_uni.c317
-rw-r--r--sys/netatm/uni/sscf_uni.h47
-rw-r--r--sys/netatm/uni/sscf_uni_lower.c379
-rw-r--r--sys/netatm/uni/sscf_uni_upper.c625
-rw-r--r--sys/netatm/uni/sscf_uni_var.h115
-rw-r--r--sys/netatm/uni/sscop.c409
-rw-r--r--sys/netatm/uni/sscop.h80
-rw-r--r--sys/netatm/uni/sscop_lower.c349
-rw-r--r--sys/netatm/uni/sscop_misc.h97
-rw-r--r--sys/netatm/uni/sscop_pdu.c1237
-rw-r--r--sys/netatm/uni/sscop_pdu.h317
-rw-r--r--sys/netatm/uni/sscop_sigaa.c449
-rw-r--r--sys/netatm/uni/sscop_sigcpcs.c2311
-rw-r--r--sys/netatm/uni/sscop_subr.c972
-rw-r--r--sys/netatm/uni/sscop_timer.c576
-rw-r--r--sys/netatm/uni/sscop_upper.c412
-rw-r--r--sys/netatm/uni/sscop_var.h283
-rw-r--r--sys/netatm/uni/uni.h50
-rw-r--r--sys/netatm/uni/uni_load.c450
-rw-r--r--sys/netatm/uni/uniarp.c1231
-rw-r--r--sys/netatm/uni/uniarp_cache.c420
-rw-r--r--sys/netatm/uni/uniarp_input.c853
-rw-r--r--sys/netatm/uni/uniarp_output.c797
-rw-r--r--sys/netatm/uni/uniarp_timer.c320
-rw-r--r--sys/netatm/uni/uniarp_vcm.c708
-rw-r--r--sys/netatm/uni/uniip.c252
-rw-r--r--sys/netatm/uni/uniip_var.h318
-rw-r--r--sys/netatm/uni/unisig.h49
-rw-r--r--sys/netatm/uni/unisig_decode.c2474
-rw-r--r--sys/netatm/uni/unisig_decode.h87
-rw-r--r--sys/netatm/uni/unisig_encode.c1681
-rw-r--r--sys/netatm/uni/unisig_if.c1012
-rw-r--r--sys/netatm/uni/unisig_mbuf.c485
-rw-r--r--sys/netatm/uni/unisig_mbuf.h58
-rw-r--r--sys/netatm/uni/unisig_msg.c1002
-rw-r--r--sys/netatm/uni/unisig_msg.h953
-rw-r--r--sys/netatm/uni/unisig_print.c877
-rw-r--r--sys/netatm/uni/unisig_print.h47
-rw-r--r--sys/netatm/uni/unisig_proto.c324
-rw-r--r--sys/netatm/uni/unisig_sigmgr_state.c860
-rw-r--r--sys/netatm/uni/unisig_subr.c1276
-rw-r--r--sys/netatm/uni/unisig_util.c389
-rw-r--r--sys/netatm/uni/unisig_var.h321
-rw-r--r--sys/netatm/uni/unisig_vc_state.c2223
132 files changed, 73729 insertions, 0 deletions
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 = &map;
+ 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)&amp->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);
+}
OpenPOWER on IntegriCloud