aboutsummaryrefslogtreecommitdiff
path: root/sys/netatm/spans/spans_cls.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/netatm/spans/spans_cls.c')
-rw-r--r--sys/netatm/spans/spans_cls.c848
1 files changed, 848 insertions, 0 deletions
diff --git a/sys/netatm/spans/spans_cls.c b/sys/netatm/spans/spans_cls.c
new file mode 100644
index 000000000000..f496311f0d39
--- /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);
+}
+