freebsd-dev/sys/netatm/spans/spans_cls.c
phk 6fd807e4f4 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).
1998-09-15 08:23:17 +00:00

849 lines
16 KiB
C

/*
*
* ===================================
* HARP | Host ATM Research Platform
* ===================================
*
*
* This Host ATM Research Platform ("HARP") file (the "Software") is
* made available by Network Computing Services, Inc. ("NetworkCS")
* "AS IS". NetworkCS does not provide maintenance, improvements or
* support of any kind.
*
* NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
* INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
* SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
* In no event shall NetworkCS be responsible for any damages, including
* but not limited to consequential damages, arising from or relating to
* any use of the Software or related support.
*
* Copyright 1994-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);
}