diff options
Diffstat (limited to 'usr.sbin/atm/scspd/scsp_input.c')
-rw-r--r-- | usr.sbin/atm/scspd/scsp_input.c | 1103 |
1 files changed, 1103 insertions, 0 deletions
diff --git a/usr.sbin/atm/scspd/scsp_input.c b/usr.sbin/atm/scspd/scsp_input.c new file mode 100644 index 0000000..21d0a07 --- /dev/null +++ b/usr.sbin/atm/scspd/scsp_input.c @@ -0,0 +1,1103 @@ +/* + * + * =================================== + * 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; +} |