summaryrefslogtreecommitdiffstats
path: root/sys/netatm
diff options
context:
space:
mode:
authorphk <phk@FreeBSD.org>1998-09-15 08:23:17 +0000
committerphk <phk@FreeBSD.org>1998-09-15 08:23:17 +0000
commitc3dd1fa899d435ea4bf79897f646a93cb80c94ac (patch)
tree98dfbc96e3c6aa7ff1f322855f6484c4e609819d /sys/netatm
parent9ed6892f4808d56de443849229e151f8f7ad43b0 (diff)
downloadFreeBSD-src-c3dd1fa899d435ea4bf79897f646a93cb80c94ac.zip
FreeBSD-src-c3dd1fa899d435ea4bf79897f646a93cb80c94ac.tar.gz
Add new files for HARP3
Host ATM Research Platform (HARP), Network Computing Services, Inc. This software was developed with the support of the Defense Advanced Research Projects Agency (DARPA).
Diffstat (limited to 'sys/netatm')
-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
100 files changed, 61962 insertions, 0 deletions
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