/* * * =================================== * HARP | Host ATM Research Platform * =================================== * * * This Host ATM Research Platform ("HARP") file (the "Software") is * made available by Network Computing Services, Inc. ("NetworkCS") * "AS IS". NetworkCS does not provide maintenance, improvements or * support of any kind. * * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED, * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE. * In no event shall NetworkCS be responsible for any damages, including * but not limited to consequential damages, arising from or relating to * any use of the Software or related support. * * Copyright 1994-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.1 1998/09/15 08:23:03 phk Exp $ * */ /* * SPANS Signalling Manager * --------------------------- * * SPANS Connectionless Datagram Service (CLS) module * */ #include #include #include #include "spans_xdr.h" #include #include #ifndef lint __RCSID("@(#) $Id: spans_cls.c,v 1.1 1998/09/15 08:23:03 phk Exp $"); #endif /* * 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); }