freebsd-skq/usr.sbin/atm/scspd/scsp_input.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

1104 lines
20 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_input.c,v 1.3 1998/08/13 20:11:15 johnc Exp $
*
*/
/*
* Server Cache Synchronization Protocol (SCSP) Support
* ----------------------------------------------------
*
* Input packet processing
*
*/
#ifndef lint
static char *RCSid = "@(#) $Id: scsp_input.c,v 1.3 1998/08/13 20:11:15 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"
static int scsp_parse_atmarp __P((char *, int, Scsp_atmarp_csa **));
/*
* Get a long ingeter
*
* This routine is provided to handle long integers that may not
* be word-aligned in the input buffer.
*
* Arguments:
* cp pointer to long int in message
*
* Returns:
* int long int in host order
*
*/
static u_long
get_long(cp)
u_char *cp;
{
int i;
u_long l;
/*
* Read the long out of the input buffer
*/
l = 0;
for (i = 0; i < sizeof(u_long); i++)
l = (l << 8) + *cp++;
/*
* Return the value in host order
*/
return(l);
}
/*
* Free an SCSP Cache Alignment message in internal format
*
* Arguments:
* cap pointer to CA message
*
* Returns:
* None
*
*/
static void
scsp_free_ca(cap)
Scsp_ca *cap;
{
Scsp_csa *csap, *ncsap;
/*
* Return if there's nothing to free
*/
if (cap == (Scsp_ca *)0)
return;
/*
* Free the CSAS records
*/
for (csap = cap->ca_csa_rec; csap; csap = ncsap) {
ncsap = csap->next;
SCSP_FREE_CSA(csap);
}
/*
* Free the CA message structure
*/
UM_FREE(cap);
}
/*
* Free an SCSP Cache State Update Request, Cache State Update Reply,
* or Cache State Update Solicit message in internal format
*
* Arguments:
* csup pointer to CSU message
*
* Returns:
* None
*
*/
static void
scsp_free_csu(csup)
Scsp_csu_msg *csup;
{
Scsp_csa *csap, *ncsap;
/*
* Return if there's nothing to free
*/
if (csup == (Scsp_csu_msg *)0)
return;
/*
* Free the CSA records
*/
for (csap = csup->csu_csa_rec; csap; csap = ncsap) {
ncsap = csap->next;
SCSP_FREE_CSA(csap);
}
/*
* Free the CSU message structure
*/
UM_FREE(csup);
}
/*
* Free an SCSP Hello message in internal format
*
* Arguments:
* hp pointer to Hello message
*
* Returns:
* None
*
*/
static void
scsp_free_hello(hp)
Scsp_hello *hp;
{
/*
* Return if there's nothing to free
*/
if (hp == (Scsp_hello *)0)
return;
/*
* Free the Hello message structure
*/
UM_FREE(hp);
}
/*
* Free an SCSP message in internal format
*
* Arguments:
* msg pointer to input packet
*
* Returns:
* None
*
*/
void
scsp_free_msg(msg)
Scsp_msg *msg;
{
Scsp_ext *exp, *nexp;
/*
* Return if there's nothing to free
*/
if (msg == (Scsp_msg *)0)
return;
/*
* Free the message body
*/
switch(msg->sc_msg_type) {
case SCSP_CA_MSG:
scsp_free_ca(msg->sc_ca);
break;
case SCSP_CSU_REQ_MSG:
case SCSP_CSU_REPLY_MSG:
case SCSP_CSUS_MSG:
scsp_free_csu(msg->sc_csu_msg);
break;
case SCSP_HELLO_MSG:
scsp_free_hello(msg->sc_hello);
break;
}
/*
* Free any extensions
*/
for (exp = msg->sc_ext; exp; exp = nexp) {
nexp = exp->next;
UM_FREE(exp);
}
/*
* Free the message structure
*/
UM_FREE(msg);
}
/*
* Parse a Sender or Receiver ID
*
* Arguments:
* buff pointer to ID
* id_len length of ID
* idp pointer to structure to receive the ID
*
* Returns:
* 0 input was invalid
* else length of ID processed
*
*/
static int
scsp_parse_id(buff, id_len, idp)
char *buff;
int id_len;
Scsp_id *idp;
{
/*
* Sanity check
*/
if (!buff ||
id_len == 0 || id_len > SCSP_MAX_ID_LEN ||
!idp) {
return(0);
}
/*
* Save the ID length
*/
idp->id_len = id_len;
/*
* Get the ID
*/
UM_COPY(buff, idp->id, id_len);
/*
* Return the ID length
*/
return(id_len);
}
/*
* Parse the Mandatory Common Part of an SCSP input packet
*
* Arguments:
* buff pointer to mandatory common part
* pdu_len length of input packet
* mcp pointer to location of MCP in decoded record
*
* Returns:
* 0 input was invalid
* else length of MCP in message
*
*/
static int
scsp_parse_mcp(buff, pdu_len, mcp)
char *buff;
int pdu_len;
Scsp_mcp *mcp;
{
int len;
u_char *idp, *odp;
struct scsp_nmcp *smp;
/*
* Get the protocol ID
*/
smp = (struct scsp_nmcp *)buff;
mcp->pid = ntohs(smp->sm_pid);
if (mcp->pid < SCSP_PROTO_ATMARP ||
mcp->pid > SCSP_PROTO_LNNI) {
/* Protocol ID is invalid */
goto mcp_invalid;
}
/*
* Get the server group ID
*/
mcp->sgid = ntohs(smp->sm_sgid);
/*
* Get the flags
*/
mcp->flags = ntohs(smp->sm_flags);
/*
* Get the sender ID and length
*/
idp = (u_char *) ((caddr_t)smp + sizeof(struct scsp_nmcp));
len = scsp_parse_id(idp, smp->sm_sid_len, &mcp->sid);
if (len == 0) {
goto mcp_invalid;
}
/*
* Get the receiver ID and length
*/
idp += len;
len = scsp_parse_id(idp, smp->sm_rid_len, &mcp->rid);
if (len == 0) {
goto mcp_invalid;
}
/*
* Get the record count
*/
mcp->rec_cnt = ntohs(smp->sm_rec_cnt);
/*
* Return the length of data we processed
*/
return(sizeof(struct scsp_nmcp) + smp->sm_sid_len +
smp->sm_rid_len);
mcp_invalid:
return(0);
}
/*
* Parse an Extension
*
* Arguments:
* buff pointer to Extension
* pdu_len length of buffer
* expp pointer to location to receive pointer to the Extension
*
* Returns:
* 0 input was invalid
* else length of Extension processed
*
*/
static int
scsp_parse_ext(buff, pdu_len, expp)
char *buff;
int pdu_len;
Scsp_ext **expp;
{
int len;
struct scsp_next *sep;
Scsp_ext *exp;
/*
* Get memory for the extension
*/
sep = (struct scsp_next *)buff;
len = sizeof(Scsp_ext) + ntohs(sep->se_len);
exp = (Scsp_ext *)UM_ALLOC(len);
if (!exp) {
goto ext_invalid;
}
UM_ZERO(exp, len);
/*
* Get the type
*/
exp->type = ntohs(sep->se_type);
/*
* Get the length
*/
exp->len = ntohs(sep->se_len);
/*
* Get the value
*/
if (exp->len > 0) {
UM_COPY((caddr_t)sep + sizeof(struct scsp_next),
(caddr_t)exp + sizeof(Scsp_ext),
exp->len);
}
/*
* Save a pointer to the extension and return the
* number of bytes processed
*/
*expp = exp;
return(sizeof(struct scsp_next) + exp->len);
ext_invalid:
if (exp) {
UM_FREE(exp);
}
return(0);
}
/*
* Parse a Cache State Advertisement or Cache State Advertisement
* Summary record
*
* Arguments:
* buff pointer to CSA or CSAS record
* pdu_len length of input packet
* csapp pointer to location to put pointer to CSA or CSAS
*
* Returns:
* 0 input was invalid
* else length of record processed
*
*/
static int
scsp_parse_csa(buff, pdu_len, csapp)
char *buff;
int pdu_len;
Scsp_csa **csapp;
{
int len;
char *idp, *odp;
struct scsp_ncsa *scp;
Scsp_csa *csap;
/*
* Check the record length
*/
scp = (struct scsp_ncsa *)buff;
if (ntohs(scp->scs_len) < (sizeof(struct scsp_ncsa) +
scp->scs_ck_len + scp->scs_oid_len)) {
goto csa_invalid;
}
/*
* Get memory for the returned structure
*/
len = sizeof(Scsp_csa) + ntohs(scp->scs_len) -
sizeof(struct scsp_ncsa) - scp->scs_ck_len -
scp->scs_oid_len;
csap = (Scsp_csa *)UM_ALLOC(len);
if (!csap) {
goto csa_invalid;
}
UM_ZERO(csap, len);
/*
* Get the hop count
*/
csap->hops = ntohs(scp->scs_hop_cnt);
/*
* Set the null flag
*/
csap->null = (ntohs(scp->scs_nfill) & SCSP_CSAS_NULL) != 0;
/*
* Get the sequence number
*/
csap->seq = get_long((u_char *)&scp->scs_seq);
/*
* Get the cache key
*/
if (scp->scs_ck_len == 0 ||
scp->scs_ck_len > SCSP_MAX_KEY_LEN) {
goto csa_invalid;
}
csap->key.key_len = scp->scs_ck_len;
idp = (char *) ((caddr_t)scp + sizeof(struct scsp_ncsa));
UM_COPY(idp, csap->key.key, scp->scs_ck_len);
/*
* Get the originator ID
*/
idp += scp->scs_ck_len;
len = scsp_parse_id(idp, scp->scs_oid_len, &csap->oid);
if (len == 0) {
goto csa_invalid;
}
/*
* Get the protocol-specific data, if present
*/
len = ntohs(scp->scs_len) - (sizeof(struct scsp_ncsa) +
scp->scs_ck_len + scp->scs_oid_len);
if (len > 0) {
idp += scp->scs_oid_len;
len = scsp_parse_atmarp(idp, len, &csap->atmarp_data);
if (len == 0)
goto csa_invalid;
}
/*
* Set a pointer to the MCP and return the length
* of data we processed
*/
*csapp = csap;
return(ntohs(scp->scs_len));
csa_invalid:
if (csap)
SCSP_FREE_CSA(csap);
return(0);
}
/*
* Parse a Cache Alignment message
*
* Arguments:
* buff pointer to start of CA in message
* pdu_len length of input packet
* capp pointer to location to put pointer to CA message
*
* Returns:
* 0 input was invalid
* else length of CA message processed
*
*/
static int
scsp_parse_ca(buff, pdu_len, capp)
char *buff;
int pdu_len;
Scsp_ca **capp;
{
int i, len, proc_len;
struct scsp_nca *scap;
Scsp_ca *cap;
Scsp_csa **csapp;
/*
* Get memory for the returned structure
*/
scap = (struct scsp_nca *)buff;
cap = (Scsp_ca *)UM_ALLOC(sizeof(Scsp_ca));
if (!cap) {
goto ca_invalid;
}
UM_ZERO(cap, sizeof(Scsp_ca));
/*
* Get the sequence number
*/
cap->ca_seq = get_long((u_char *)&scap->sca_seq);
proc_len = sizeof(scap->sca_seq);
buff += sizeof(scap->sca_seq);
/*
* Process the mandatory common part of the message
*/
len = scsp_parse_mcp(buff,
pdu_len - proc_len,
&cap->ca_mcp);
if (len == 0)
goto ca_invalid;
buff += len;
proc_len += len;
/*
* Set the flags
*/
cap->ca_m = (cap->ca_mcp.flags & SCSP_CA_M) != 0;
cap->ca_i = (cap->ca_mcp.flags & SCSP_CA_I) != 0;
cap->ca_o = (cap->ca_mcp.flags & SCSP_CA_O) != 0;
/*
* Get the CSAS records from the message
*/
for (i = 0, csapp = &cap->ca_csa_rec; i < cap->ca_mcp.rec_cnt;
i++, csapp = &(*csapp)->next) {
len = scsp_parse_csa(buff, pdu_len - proc_len, csapp);
buff += len;
proc_len += len;
}
/*
* Set the address of the CA message and
* return the length of processed data
*/
*capp = cap;
return(proc_len);
ca_invalid:
if (cap)
scsp_free_ca(cap);
return(0);
}
/*
* Parse the ATMARP-specific part of a CSA record
*
* Arguments:
* buff pointer to ATMARP part of CSU message
* pdu_len length of data to process
* acspp pointer to location to put pointer to CSU message
*
* Returns:
* 0 input was invalid
* else length of CSU Req message processed
*
*/
static int
scsp_parse_atmarp(buff, pdu_len, acspp)
char *buff;
int pdu_len;
Scsp_atmarp_csa **acspp;
{
int i, len, proc_len;
struct scsp_atmarp_ncsa *sacp;
Scsp_atmarp_csa *acsp;
/*
* Initial packet verification
*/
sacp = (struct scsp_atmarp_ncsa *)buff;
if ((sacp->sa_hrd != ntohs(ARP_ATMFORUM)) ||
(sacp->sa_pro != ntohs(ETHERTYPE_IP)))
goto acs_invalid;
/*
* Get memory for the returned structure
*/
acsp = (Scsp_atmarp_csa *)UM_ALLOC(sizeof(Scsp_atmarp_csa));
if (!acsp) {
goto acs_invalid;
}
UM_ZERO(acsp, sizeof(Scsp_atmarp_csa));
/*
* Get state code
*/
acsp->sa_state = sacp->sa_state;
proc_len = sizeof(struct scsp_atmarp_ncsa);
/*
* Verify/gather source ATM address
*/
acsp->sa_sha.address_format = T_ATM_ABSENT;
acsp->sa_sha.address_length = 0;
if (len = (sacp->sa_shtl & ARP_TL_LMASK)) {
if (sacp->sa_shtl & ARP_TL_E164) {
if (len > sizeof(Atm_addr_e164))
goto acs_invalid;
acsp->sa_sha.address_format = T_ATM_E164_ADDR;
} else {
if (len != sizeof(Atm_addr_nsap))
goto acs_invalid;
acsp->sa_sha.address_format = T_ATM_ENDSYS_ADDR;
}
acsp->sa_sha.address_length = len;
if (pdu_len < proc_len + len)
goto acs_invalid;
UM_COPY(&buff[proc_len], (char *)acsp->sa_sha.address,
len);
proc_len += len;
}
/*
* Verify/gather source ATM subaddress
*/
acsp->sa_ssa.address_format = T_ATM_ABSENT;
acsp->sa_ssa.address_length = 0;
if (len = (sacp->sa_sstl & ARP_TL_LMASK)) {
if (((sacp->sa_sstl & ARP_TL_TMASK) != ARP_TL_NSAPA) ||
(len != sizeof(Atm_addr_nsap)))
goto acs_invalid;
acsp->sa_ssa.address_format = T_ATM_ENDSYS_ADDR;
acsp->sa_ssa.address_length = len;
if (pdu_len < proc_len + len)
goto acs_invalid;
UM_COPY(&buff[proc_len], (char *)acsp->sa_ssa.address,
len);
proc_len += len;
}
/*
* Verify/gather source IP address
*/
if (len = sacp->sa_spln) {
if (len != sizeof(struct in_addr))
goto acs_invalid;
if (pdu_len < proc_len + len)
goto acs_invalid;
UM_COPY(&buff[proc_len], (char *)&acsp->sa_spa, len);
proc_len += len;
} else {
acsp->sa_spa.s_addr = 0;
}
/*
* Verify/gather target ATM address
*/
acsp->sa_tha.address_format = T_ATM_ABSENT;
acsp->sa_tha.address_length = 0;
if (len = (sacp->sa_thtl & ARP_TL_LMASK)) {
if (sacp->sa_thtl & ARP_TL_E164) {
if (len > sizeof(Atm_addr_e164))
goto acs_invalid;
acsp->sa_tha.address_format = T_ATM_E164_ADDR;
} else {
if (len != sizeof(Atm_addr_nsap))
goto acs_invalid;
acsp->sa_tha.address_format = T_ATM_ENDSYS_ADDR;
}
acsp->sa_tha.address_length = len;
if (pdu_len < proc_len + len)
goto acs_invalid;
UM_COPY(&buff[proc_len], (char *)acsp->sa_tha.address,
len);
proc_len += len;
}
/*
* Verify/gather target ATM subaddress
*/
acsp->sa_tsa.address_format = T_ATM_ABSENT;
acsp->sa_tsa.address_length = 0;
if (len = (sacp->sa_tstl & ARP_TL_LMASK)) {
if (((sacp->sa_tstl & ARP_TL_TMASK) != ARP_TL_NSAPA) ||
(len != sizeof(Atm_addr_nsap)))
goto acs_invalid;
acsp->sa_tsa.address_format = T_ATM_ENDSYS_ADDR;
acsp->sa_tsa.address_length = len;
if (pdu_len < proc_len + len)
goto acs_invalid;
UM_COPY(&buff[proc_len], (char *)acsp->sa_tsa.address,
len);
proc_len += len;
}
/*
* Verify/gather target IP address
*/
if (len = sacp->sa_tpln) {
if (len != sizeof(struct in_addr))
goto acs_invalid;
if (pdu_len < proc_len + len)
goto acs_invalid;
UM_COPY(&buff[proc_len], (char *)&acsp->sa_tpa, len);
proc_len += len;
} else {
acsp->sa_tpa.s_addr = 0;
}
/*
* Verify packet length
*/
if (proc_len != pdu_len)
goto acs_invalid;
*acspp = acsp;
return(proc_len);
acs_invalid:
if (acsp)
UM_FREE(acsp);
return(0);
}
/*
* Parse 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:
* buff pointer to start of CSU message
* pdu_len length of input packet
* csupp pointer to location to put pointer to CSU message
*
* Returns:
* 0 input was invalid
* else length of CSU Req message processed
*
*/
static int
scsp_parse_csu(buff, pdu_len, csupp)
char *buff;
int pdu_len;
Scsp_csu_msg **csupp;
{
int i, len, proc_len;
Scsp_csu_msg *csup;
Scsp_csa **csapp;
/*
* Get memory for the returned structure
*/
csup = (Scsp_csu_msg *)UM_ALLOC(sizeof(Scsp_csu_msg));
if (!csup) {
goto csu_invalid;
}
UM_ZERO(csup, sizeof(Scsp_csu_msg));
/*
* Process the mandatory common part of the message
*/
len = scsp_parse_mcp(buff, pdu_len, &csup->csu_mcp);
if (len == 0)
goto csu_invalid;
buff += len;
proc_len = len;
/*
* Get the CSAS records from the message
*/
for (i = 0, csapp = &csup->csu_csa_rec;
i < csup->csu_mcp.rec_cnt;
i++, csapp = &(*csapp)->next) {
len = scsp_parse_csa(buff, pdu_len - proc_len, csapp);
buff += len;
proc_len += len;
}
/*
* Set the address of the CSU Req message and
* return the length of processed data
*/
*csupp = csup;
return(proc_len);
csu_invalid:
if (csup)
scsp_free_csu(csup);
return(0);
}
/*
* Parse a Hello message
*
* Arguments:
* buff pointer to start of Hello in message
* pdu_len length of input packet
* hpp pointer to location to put pointer to Hello message
*
* Returns:
* 0 input was invalid
* else length of Hello message processed
*
*/
static int
scsp_parse_hello(buff, pdu_len, hpp)
char *buff;
int pdu_len;
Scsp_hello **hpp;
{
int i, len, proc_len;
struct scsp_nhello *shp = (struct scsp_nhello *)buff;
Scsp_hello *hp;
Scsp_id *idp;
Scsp_id **ridpp;
/*
* Get memory for the returned structure
*/
hp = (Scsp_hello *)UM_ALLOC(sizeof(Scsp_hello));
if (!hp) {
goto hello_invalid;
}
UM_ZERO(hp, sizeof(Scsp_hello));
/*
* Get the hello interval
*/
hp->hello_int = ntohs(shp->sch_hi);
/*
* Get the dead factor
*/
hp->dead_factor = ntohs(shp->sch_df);
/*
* Get the family ID
*/
hp->family_id = ntohs(shp->sch_fid);
/*
* Process the mandatory common part of the message
*/
proc_len = sizeof(struct scsp_nhello) -
sizeof(struct scsp_nmcp);
buff += proc_len;
len = scsp_parse_mcp(buff, pdu_len - proc_len,
&hp->hello_mcp);
if (len == 0)
goto hello_invalid;
buff += len;
proc_len += len;
/*
* Get additional receiver ID records from the message
*/
for (i = 0, ridpp = &hp->hello_mcp.rid.next;
i < hp->hello_mcp.rec_cnt;
i++, ridpp = &idp->next) {
idp = (Scsp_id *)UM_ALLOC(sizeof(Scsp_id));
if (!idp) {
goto hello_invalid;
}
UM_ZERO(idp, sizeof(Scsp_id));
len = scsp_parse_id(buff,
hp->hello_mcp.rid.id_len,
idp);
if (len == 0) {
UM_FREE(idp);
goto hello_invalid;
}
buff += len;
proc_len += len;
*ridpp = idp;
}
/*
* Set the address of the CA message and
* return the length of processed data
*/
*hpp = hp;
return(proc_len);
hello_invalid:
if (hp)
scsp_free_hello(hp);
return(0);
}
/*
* Parse an SCSP input packet
*
* Arguments:
* buff pointer to input packet
* pdu_len length of input packet
*
* Returns:
* NULL input packet was invalid
* else pointer to packet in internal format
*
*/
Scsp_msg *
scsp_parse_msg(buff, pdu_len)
char *buff;
int pdu_len;
{
int ext_off, len, plen;
struct scsp_nhdr *shp;
Scsp_msg *msg = (Scsp_msg *)0;
Scsp_ext **expp;
/*
* Check the message checksum
*/
if (ip_checksum(buff, pdu_len) != 0) {
/*
* Checksum was bad--discard the message
*/
goto ignore;
}
/*
* Allocate storage for the message
*/
msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg));
if (!msg) {
goto ignore;
}
UM_ZERO(msg, sizeof(Scsp_msg));
/*
* Decode the fixed header
*
* Check the version
*/
shp = (struct scsp_nhdr *)buff;
if (shp->sh_ver != SCSP_VER_1)
goto ignore;
/*
* Get the message type
*/
msg->sc_msg_type = shp->sh_type;
/*
* Get and check the length
*/
len = ntohs(shp->sh_len);
if (len != pdu_len)
goto ignore;
/*
* Get the extension offset
*/
ext_off = ntohs(shp->sh_ext_off);
/*
* Decode the body of the message, depending on the type
*/
buff += sizeof(struct scsp_nhdr);
len -= sizeof(struct scsp_nhdr);
switch(msg->sc_msg_type) {
case SCSP_CA_MSG:
plen = scsp_parse_ca(buff, len, &msg->sc_ca);
break;
case SCSP_CSU_REQ_MSG:
case SCSP_CSU_REPLY_MSG:
case SCSP_CSUS_MSG:
plen = scsp_parse_csu(buff, len, &msg->sc_csu_msg);
break;
case SCSP_HELLO_MSG:
plen = scsp_parse_hello(buff, len, &msg->sc_hello);
break;
default:
goto ignore;
}
if (plen == 0) {
goto ignore;
}
buff += plen;
len -= plen;
/*
* Decode any extensions
*/
if (ext_off != 0) {
for (expp = &msg->sc_ext; len > 0;
expp = &(*expp)->next) {
plen = scsp_parse_ext(buff, len, expp);
if (plen == 0) {
goto ignore;
}
buff += plen;
len -= plen;
}
}
/*
* Make sure we handled the whole message
*/
if (len != 0) {
goto ignore;
}
/*
* Return the address of the SCSP message in internal format
*/
return(msg);
ignore:
if (msg)
scsp_free_msg(msg);
return(Scsp_msg *)0;
}