summaryrefslogtreecommitdiffstats
path: root/usr.sbin/atm/scspd/scsp_input.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/atm/scspd/scsp_input.c')
-rw-r--r--usr.sbin/atm/scspd/scsp_input.c1103
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;
+}
OpenPOWER on IntegriCloud