freebsd-dev/usr.sbin/atm/scspd/scsp_output.c
Poul-Henning Kamp 1820df7a2d 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

935 lines
17 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: scsp_output.c,v 1.2 1998/07/12 20:49:45 johnc Exp $
*
*/
/*
* Server Cache Synchronization Protocol (SCSP) Support
* ----------------------------------------------------
*
* Output packet processing
*
*/
#ifndef lint
static char *RCSid = "@(#) $Id: scsp_output.c,v 1.2 1998/07/12 20:49:45 johnc Exp $";
#endif
#include <sys/types.h>
#include <sys/param.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <syslog.h>
#include <sys/socket.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/if_ether.h>
#include <netatm/port.h>
#include <netatm/queue.h>
#include <netatm/atm.h>
#include <netatm/atm_if.h>
#include <netatm/atm_sap.h>
#include <netatm/atm_sys.h>
#include <netatm/atm_ioctl.h>
#include <libatm.h>
#include "scsp_msg.h"
#include "scsp_if.h"
#include "scsp_var.h"
/*
* Put a long integer into the output buffer
*
* This routine is provided for cases where long ints may not be
* word-aligned in the output buffer.
*
* Arguments:
* l long integer
* cp pointer to output buffer
*
* Returns:
* None
*
*/
static void
put_long(l, cp)
u_long l;
u_char *cp;
{
u_long nl;
/*
* Convert to network order and copy to output buffer
*/
nl = htonl(l);
UM_COPY(&nl, cp, sizeof(u_long));
}
/*
* Format a Sender or Receiver ID
*
* Arguments:
* idp ponter to ID structure
* buff pointer to ID
*
* Returns:
* 0 input was invalid
* else length of ID processed
*
*/
static int
scsp_format_id(idp, buff)
Scsp_id *idp;
char *buff;
{
/*
* Copy the ID
*/
UM_COPY(idp->id, buff, idp->id_len);
/*
* Return the ID length
*/
return(idp->id_len);
}
/*
* Format the Mandatory Common Part of an SCSP input packet
*
* Arguments:
* mcp pointer to MCP
* buff pointer to mandatory common part
*
* Returns:
* 0 input was invalid
* else length of MCP in message
*
*/
static int
scsp_format_mcp(mcp, buff)
Scsp_mcp *mcp;
char *buff;
{
int len;
char *idp, *odp;
struct scsp_nmcp *smp;
/*
* Set the protocol ID
*/
smp = (struct scsp_nmcp *)buff;
smp->sm_pid = htons(mcp->pid);
/*
* Set the server group ID
*/
smp->sm_sgid = htons(mcp->sgid);
/*
* Set the flags
*/
smp->sm_flags = htons(mcp->flags);
/*
* Set the sender ID and length
*/
smp->sm_sid_len = mcp->sid.id_len;
odp = buff + sizeof(struct scsp_nmcp);
len = scsp_format_id(&mcp->sid, odp);
if (len == 0) {
goto mcp_invalid;
}
/*
* Set the receiver ID and length
*/
smp->sm_rid_len = mcp->rid.id_len;
odp += mcp->sid.id_len;
len = scsp_format_id(&mcp->rid, odp);
if (len == 0) {
goto mcp_invalid;
}
/*
* Set the record count
*/
smp->sm_rec_cnt = htons(mcp->rec_cnt);
/*
* Return the length of data we processed
*/
return(sizeof(struct scsp_nmcp) + mcp->sid.id_len +
mcp->rid.id_len);
mcp_invalid:
return(0);
}
/*
* Format an Extension
*
* Arguments:
* exp pointer to extension in internal format
* buff pointer to output buffer
* blen space available in buffer
*
* Returns:
* 0 input was invalid
* else length of extension processed
*
*/
static int
scsp_format_ext(exp, buff, blen)
Scsp_ext *exp;
char *buff;
int blen;
{
int len;
struct scsp_next *sep;
/*
* Make sure there's room in the buffer
*/
if (blen < (sizeof(struct scsp_next) + exp->len))
return(0);
/*
* Set the type
*/
sep = (struct scsp_next *)buff;
sep->se_type = htons(exp->type);
/*
* Set the length
*/
sep->se_len = htons(exp->len);
/*
* Set the value
*/
if (exp->len > 0) {
buff += sizeof(struct scsp_next);
UM_COPY((caddr_t)exp + sizeof(Scsp_ext),
buff,
exp->len);
}
/*
* Return the number of bytes processed
*/
return(sizeof(struct scsp_next) + exp->len);
}
/*
* Format the ATMARP part of a CSA record
*
* Arguments:
* acsp pointer to ATMARP protocol-specific CSA record
* buff pointer to output buffer
*
* Returns:
* 0 input was invalid
* else length of record processed
*
*/
static int
scsp_format_atmarp(acsp, buff)
Scsp_atmarp_csa *acsp;
char *buff;
{
char *cp;
int len, pkt_len, rc;
struct scsp_atmarp_ncsa *sanp;
/*
* Figure out how long PDU is going to be
*/
pkt_len = sizeof(struct scsp_atmarp_ncsa);
switch (acsp->sa_sha.address_format) {
case T_ATM_ENDSYS_ADDR:
pkt_len += acsp->sa_sha.address_length;
break;
case T_ATM_E164_ADDR:
pkt_len += acsp->sa_sha.address_length;
if (acsp->sa_ssa.address_format == T_ATM_ENDSYS_ADDR)
pkt_len += acsp->sa_ssa.address_length;
break;
}
switch (acsp->sa_tha.address_format) {
case T_ATM_ENDSYS_ADDR:
pkt_len += acsp->sa_tha.address_length;
break;
case T_ATM_E164_ADDR:
pkt_len += acsp->sa_tha.address_length;
if (acsp->sa_tha.address_format == T_ATM_ENDSYS_ADDR)
pkt_len += acsp->sa_tha.address_length;
break;
}
if (acsp->sa_spa.s_addr != 0)
pkt_len += sizeof(struct in_addr);
if (acsp->sa_tpa.s_addr != 0)
pkt_len += sizeof(struct in_addr);
/*
* Set up pointers
*/
sanp = (struct scsp_atmarp_ncsa *)buff;
cp = (char *)sanp + sizeof(struct scsp_atmarp_ncsa);
/*
* Build fields
*/
sanp->sa_hrd = htons(ARP_ATMFORUM);
sanp->sa_pro = htons(ETHERTYPE_IP);
/* sa_sha */
len = acsp->sa_sha.address_length;
switch (acsp->sa_sha.address_format) {
case T_ATM_ENDSYS_ADDR:
sanp->sa_shtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
/* sa_sha */
UM_COPY(acsp->sa_sha.address, cp, len);
cp += len;
sanp->sa_sstl = 0;
break;
case T_ATM_E164_ADDR:
sanp->sa_shtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
/* sa_sha */
UM_COPY(acsp->sa_sha.address, cp, len);
cp += len;
if (acsp->sa_ssa.address_format == T_ATM_ENDSYS_ADDR) {
len = acsp->sa_ssa.address_length;
sanp->sa_sstl = ARP_TL_NSAPA |
(len & ARP_TL_LMASK);
/* sa_ssa */
UM_COPY(acsp->sa_ssa.address, cp, len);
cp += len;
} else
sanp->sa_sstl = 0;
break;
default:
sanp->sa_shtl = 0;
sanp->sa_sstl = 0;
}
/* sa_state */
sanp->sa_state = acsp->sa_state;
sanp->sa_fill1 = 0;
/* sa_spa */
if (acsp->sa_spa.s_addr != 0) {
sanp->sa_spln = sizeof(struct in_addr);
UM_COPY(&acsp->sa_spa, cp, sizeof(struct in_addr));
cp += sizeof(struct in_addr);
}
/* sa_tha */
len = acsp->sa_tha.address_length;
switch (acsp->sa_tha.address_format) {
case T_ATM_ENDSYS_ADDR:
sanp->sa_thtl = ARP_TL_NSAPA | (len & ARP_TL_LMASK);
/* sa_tha */
UM_COPY(acsp->sa_tha.address, cp, len);
cp += len;
sanp->sa_tstl = 0;
break;
case T_ATM_E164_ADDR:
sanp->sa_thtl = ARP_TL_E164 | (len & ARP_TL_LMASK);
/* sa_tha */
UM_COPY(acsp->sa_tha.address, cp, len);
cp += len;
if (acsp->sa_tsa.address_format == T_ATM_ENDSYS_ADDR) {
len = acsp->sa_tha.address_length;
sanp->sa_tstl = ARP_TL_NSAPA |
(len & ARP_TL_LMASK);
/* sa_tsa */
UM_COPY(acsp->sa_tsa.address, cp, len);
cp += len;
} else
sanp->sa_tstl = 0;
break;
default:
sanp->sa_thtl = 0;
sanp->sa_tstl = 0;
}
/* sa_tpa */
if (acsp->sa_tpa.s_addr != 0) {
sanp->sa_tpln = sizeof(struct in_addr);
UM_COPY(&acsp->sa_tpa, cp, sizeof(struct in_addr));
}
return(pkt_len);
}
/*
* Format a Cache State Advertisement or Cache State Advertisement
* Summary record
*
* Arguments:
* csapp pointer to CSA or CSAS
* buff pointer to output buffer
*
* Returns:
* 0 input was invalid
* else length of record processed
*
*/
static int
scsp_format_csa(csap, buff)
Scsp_csa *csap;
char *buff;
{
int len = 0;
char *idp, *odp;
struct scsp_ncsa *scp;
/*
* Set the hop count
*/
scp = (struct scsp_ncsa *)buff;
scp->scs_hop_cnt = htons(csap->hops);
/*
* Set the null flag
*/
if (csap->null) {
scp->scs_nfill = htons(SCSP_CSAS_NULL);
}
/*
* Set the sequence number
*/
put_long(csap->seq, (u_char *)&scp->scs_seq);
/*
* Set the cache key
*/
scp->scs_ck_len = csap->key.key_len;
odp = buff + sizeof(struct scsp_ncsa);
UM_COPY(csap->key.key, odp, scp->scs_ck_len);
/*
* Set the originator ID
*/
odp += scp->scs_ck_len;
scp->scs_oid_len = scsp_format_id(&csap->oid, odp);
/*
* Set the protocol-specific data, if present. At the
* moment, we only handle data for ATMARP.
*/
if (csap->atmarp_data) {
odp += scp->scs_oid_len;
len = scsp_format_atmarp(csap->atmarp_data, odp);
}
/*
* Set the record length
*/
scp->scs_len = htons(sizeof(struct scsp_ncsa) +
scp->scs_ck_len + scp->scs_oid_len +
len);
/*
* Return the length of data we processed
*/
return(ntohs(scp->scs_len));
}
/*
* Format a Cache Alignment message
*
* Arguments:
* cap pointer to CA message
* buff pointer to output buffer
* blen space available in buffer
*
* Returns:
* 0 input was invalid
* else length of CA message processed
*
*/
static int
scsp_format_ca(cap, buff, blen)
Scsp_ca *cap;
char *buff;
int blen;
{
int i, len, proc_len;
struct scsp_nca *scap;
Scsp_csa *csap;
/*
* Set the sequence number
*/
scap = (struct scsp_nca *)buff;
put_long(cap->ca_seq, (u_char *)&scap->sca_seq);
proc_len = sizeof(scap->sca_seq);
buff += sizeof(scap->sca_seq);
/*
* Set the flags
*/
cap->ca_mcp.flags = 0;
if (cap->ca_m)
cap->ca_mcp.flags |= SCSP_CA_M;
if (cap->ca_i)
cap->ca_mcp.flags |= SCSP_CA_I;
if (cap->ca_o)
cap->ca_mcp.flags |= SCSP_CA_O;
/*
* Format the mandatory common part of the message
*/
len = scsp_format_mcp(&cap->ca_mcp, buff);
if (len == 0)
goto ca_invalid;
buff += len;
proc_len += len;
/*
* Put any CSAS records into the message
*/
for (i = 0, csap = cap->ca_csa_rec; i < cap->ca_mcp.rec_cnt;
i++, csap = csap->next) {
len = scsp_format_csa(csap, buff);
buff += len;
proc_len += len;
if (proc_len > blen) {
scsp_log(LOG_CRIT, "scsp_format_ca: buffer overflow");
abort();
}
}
/*
* Return the length of processed data
*/
return(proc_len);
ca_invalid:
return(0);
}
/*
* Format a Cache State Update Request, Cache State Update Reply, or
* Cache State Update Solicit message. These all have the same format,
* a Mandatory Common Part followed by a number of CSA or CSAS records.
*
* Arguments:
* csup pointer to location to put pointer to CSU Req message
* buff pointer to output buffer
* blen space available in buffer
*
* Returns:
* 0 input was invalid
* else length of CSU Req message processed
*
*/
static int
scsp_format_csu(csup, buff, blen)
Scsp_csu_msg *csup;
char *buff;
int blen;
{
int i, len, proc_len;
struct scsp_ncsu_msg *scsup;
Scsp_csa *csap;
/*
* Format the mandatory common part of the message
*/
scsup = (struct scsp_ncsu_msg *)buff;
len = scsp_format_mcp(&csup->csu_mcp, buff);
if (len == 0)
goto csu_invalid;
buff += len;
proc_len = len;
/*
* Put the CSAS records into the message
*/
for (i = 0, csap = csup->csu_csa_rec;
i < csup->csu_mcp.rec_cnt && csap;
i++, csap = csap->next) {
len = scsp_format_csa(csap, buff);
buff += len;
proc_len += len;
if (proc_len > blen) {
scsp_log(LOG_CRIT, "scsp_format_csu: buffer overflow");
abort();
}
}
/*
* Return the length of processed data
*/
return(proc_len);
csu_invalid:
return(0);
}
/*
* Format a Hello message
*
* Arguments:
* hpp pointer to Hello message
* buff pointer to output buffer
* blen space available in buffer
*
* Returns:
* 0 input was invalid
* else length of Hello message processed
*
*/
static int
scsp_format_hello(hp, buff, blen)
Scsp_hello *hp;
char *buff;
int blen;
{
int i, len, proc_len;
struct scsp_nhello *shp;
Scsp_id *idp;
Scsp_id *ridp;
/*
* Set the hello interval
*/
shp = (struct scsp_nhello *)buff;
shp->sch_hi = htons(hp->hello_int);
/*
* Set the dead factor
*/
shp->sch_df = htons(hp->dead_factor);
/*
* Set the family ID
*/
shp->sch_fid = htons(hp->family_id);
/*
* Process the mandatory common part of the message
*/
proc_len = sizeof(struct scsp_nhello) -
sizeof(struct scsp_nmcp);
buff += proc_len;
len = scsp_format_mcp(&hp->hello_mcp, buff);
if (len == 0)
goto hello_invalid;
proc_len += len;
buff += len;
/*
* Add any additional receiver ID records to the message
*/
for (ridp = hp->hello_mcp.rid.next; ridp;
ridp = ridp->next) {
len = scsp_format_id(ridp, buff);
if (len == 0) {
goto hello_invalid;
}
proc_len += len;
buff += len;
}
/*
* Return the length of the Hello message body
*/
if (proc_len > blen) {
scsp_log(LOG_CRIT, "scsp_format_hello: buffer overflow");
abort();
}
return(proc_len);
hello_invalid:
return(0);
}
/*
* Format an SCSP output packet
*
* Arguments:
* dcsp pointer to DCS for which message is being prepared
* msg pointer to input packet
* bpp pointer to location to put pointer to formatted packet
*
* Returns:
* 0 input packet was invalid
* else length of formatted packet
*
*/
int
scsp_format_msg(dcsp, msg, bpp)
Scsp_dcs *dcsp;
Scsp_msg *msg;
char **bpp;
{
char *buff = (char *)0, *e_buff = (char *)0;
int buff_len, e_buff_len;
int e_len, len, plen;
struct scsp_nhdr *shp;
Scsp_ext *exp;
/*
* Allocate a buffer for the message
*/
buff_len = dcsp->sd_server->ss_mtu;
buff = (char *)UM_ALLOC(buff_len);
if (!buff) {
scsp_mem_err("scsp_format_msg: dcsp->sd_server->ss_mtu");
}
UM_ZERO(buff, buff_len);
*bpp = buff;
/*
* Encode the fixed header
*
* Set the version
*/
shp = (struct scsp_nhdr *)buff;
shp->sh_ver = SCSP_VER_1;
/*
* Set the message type
*/
shp->sh_type = msg->sc_msg_type;
/*
* Point past the fixed header
*/
len = sizeof(struct scsp_nhdr);
buff_len -= len;
/*
* Encode any extensions into a temporary buffer
*/
e_len = 0;
if (msg->sc_ext) {
/*
* Get a buffer for the extensions
*/
e_buff_len = 1024;
e_buff = (char *)UM_ALLOC(e_buff_len);
if (!buff) {
scsp_mem_err("scsp_format_msg: e_buff_len");
}
UM_ZERO(e_buff, e_buff_len);
/*
* Encode the extensions
*/
for (exp = msg->sc_ext = 0; exp; exp = exp->next) {
plen = scsp_format_ext(exp, e_buff + e_len,
e_buff_len - e_len);
if (plen == 0) {
goto ignore;
}
e_len += plen;
}
/*
* Free the buffer if we didn't use it
*/
if (!e_len) {
UM_FREE(e_buff);
e_buff = (char *)0;
}
}
buff_len -= e_len;
/*
* Encode the body of the message, depending on the type
*/
switch(msg->sc_msg_type) {
case SCSP_CA_MSG:
plen = scsp_format_ca(msg->sc_ca, buff + len, buff_len);
break;
case SCSP_CSU_REQ_MSG:
case SCSP_CSU_REPLY_MSG:
case SCSP_CSUS_MSG:
plen = scsp_format_csu(msg->sc_csu_msg, buff + len,
buff_len);
break;
case SCSP_HELLO_MSG:
plen = scsp_format_hello(msg->sc_hello, buff + len,
buff_len);
break;
default:
goto ignore;
}
if (plen == 0) {
goto ignore;
}
len += plen;
/*
* Copy the extensions to the end of the message
*/
if (e_len) {
shp->sh_ext_off = htons(len);
UM_COPY(e_buff, buff + len, e_len);
UM_FREE(e_buff);
}
/*
* Set the length
*/
shp->sh_len = htons(len);
/*
* Compute the message checksum
*/
shp->sh_checksum = htons(ip_checksum(buff, len));
/*
* Return the length of the buffer
*/
return(len);
ignore:
if (buff)
UM_FREE(buff);
if (e_buff)
UM_FREE(e_buff);
*bpp = (char *)0;
return(0);
}
/*
* Send an SCSP message
*
* Arguments:
* dcsp pointer to DCS control block
* msg pointer to message to send
*
* Returns:
* 0 success
* errno error encountered
*
*/
int
scsp_send_msg(dcsp, msg)
Scsp_dcs *dcsp;
Scsp_msg *msg;
{
int len, rc;
char *buff;
/*
* Make sure we have a socket open
*/
if (dcsp->sd_sock == -1) {
return(EBADF);
}
/*
* Trace the message
*/
if (((scsp_trace_mode & SCSP_TRACE_HELLO_MSG) &&
msg->sc_msg_type == SCSP_HELLO_MSG) ||
((scsp_trace_mode & SCSP_TRACE_CA_MSG) &&
msg->sc_msg_type != SCSP_HELLO_MSG)) {
scsp_trace_msg(dcsp, msg, 0);
scsp_trace("\n");
}
/*
* Put the message into network format
*/
len = scsp_format_msg(dcsp, msg, &buff);
if (len == 0) {
scsp_log(LOG_ERR, "scsp_send_msg: message conversion failed\n");
abort();
}
/*
* Write the message to the DCS
*/
rc = write(dcsp->sd_sock, (void *)buff, len);
UM_FREE(buff);
if (rc == len || (rc == -1 && errno == EINPROGRESS)) {
rc = 0;
} else {
/*
* There was an error on the write--close the VCC
*/
(void)close(dcsp->sd_sock);
dcsp->sd_sock = -1;
/*
* Inform the Hello FSM
*/
(void)scsp_hfsm(dcsp, SCSP_HFSM_VC_CLOSED,
(Scsp_msg *)0);
/*
* Set the return code
*/
if (rc == -1)
rc = errno;
else
rc = EINVAL;
}
return(rc);
}