]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/atm/scspd/scsp_input.c
This commit was generated by cvs2svn to compensate for changes in r172665,
[FreeBSD/FreeBSD.git] / usr.sbin / atm / scspd / scsp_input.c
1 /*
2  *
3  * ===================================
4  * HARP  |  Host ATM Research Platform
5  * ===================================
6  *
7  *
8  * This Host ATM Research Platform ("HARP") file (the "Software") is
9  * made available by Network Computing Services, Inc. ("NetworkCS")
10  * "AS IS".  NetworkCS does not provide maintenance, improvements or
11  * support of any kind.
12  *
13  * NETWORKCS MAKES NO WARRANTIES OR REPRESENTATIONS, EXPRESS OR IMPLIED,
14  * INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY
15  * AND FITNESS FOR A PARTICULAR PURPOSE, AS TO ANY ELEMENT OF THE
16  * SOFTWARE OR ANY SUPPORT PROVIDED IN CONNECTION WITH THIS SOFTWARE.
17  * In no event shall NetworkCS be responsible for any damages, including
18  * but not limited to consequential damages, arising from or relating to
19  * any use of the Software or related support.
20  *
21  * Copyright 1994-1998 Network Computing Services, Inc.
22  *
23  * Copies of this Software may be made, however, the above copyright
24  * notice must be reproduced on all copies.
25  *
26  *      @(#) $FreeBSD$
27  *
28  */
29
30 /*
31  * Server Cache Synchronization Protocol (SCSP) Support
32  * ----------------------------------------------------
33  *
34  * Input packet processing
35  *
36  */
37
38 #include <sys/types.h>
39 #include <sys/param.h>
40 #include <sys/socket.h>
41 #include <net/ethernet.h>
42 #include <net/if.h>
43 #include <netinet/in.h>
44 #include <netatm/port.h> 
45 #include <netatm/queue.h> 
46 #include <netatm/atm.h>
47 #include <netatm/atm_if.h>
48 #include <netatm/atm_sap.h>
49 #include <netatm/atm_sys.h>
50 #include <netatm/atm_ioctl.h>
51   
52 #include <errno.h>
53 #include <libatm.h>
54 #include <stdio.h>
55 #include <stdlib.h>
56 #include <string.h>
57 #include <syslog.h>
58
59 #include "scsp_msg.h"
60 #include "scsp_if.h"
61 #include "scsp_var.h"
62
63 #ifndef lint
64 __RCSID("@(#) $FreeBSD$");
65 #endif
66
67
68 static int scsp_parse_atmarp(char *, int, Scsp_atmarp_csa **);
69
70
71 /*
72  * Get a long ingeter
73  *
74  * This routine is provided to handle long integers that may not
75  * be word-aligned in the input buffer.
76  *
77  * Arguments:
78  *      cp      pointer to long int in message
79  *
80  * Returns:
81  *      int     long int in host order
82  *
83  */
84 static u_long
85 get_long(cp)
86         u_char  *cp;
87 {
88         int     i;
89         u_long  l;
90
91         /*
92          * Read the long out of the input buffer
93          */
94         l = 0;
95         for (i = 0; i < sizeof(u_long); i++)
96                 l = (l << 8) + *cp++;
97
98         /*
99          * Return the value in host order
100          */
101         return(l);
102 }
103
104
105 /*
106  * Free an SCSP Cache Alignment message in internal format
107  *
108  * Arguments:
109  *      cap     pointer to CA message
110  *
111  * Returns:
112  *      None
113  *
114  */
115 static void
116 scsp_free_ca(cap)
117         Scsp_ca *cap;
118 {
119         Scsp_csa        *csap, *ncsap;
120
121         /*
122          * Return if there's nothing to free
123          */
124         if (cap == (Scsp_ca *)0)
125                 return;
126
127         /*
128          * Free the CSAS records
129          */
130         for (csap = cap->ca_csa_rec; csap; csap = ncsap) {
131                 ncsap = csap->next;
132                 SCSP_FREE_CSA(csap);
133         }
134         /*
135          * Free the CA message structure
136          */
137         free(cap);
138 }
139
140
141 /*
142  * Free an SCSP Cache State Update Request, Cache State Update Reply,
143  * or Cache State Update Solicit message in internal format
144  *
145  * Arguments:
146  *      csup    pointer to CSU message
147  *
148  * Returns:
149  *      None
150  *
151  */
152 static void
153 scsp_free_csu(csup)
154         Scsp_csu_msg    *csup;
155 {
156         Scsp_csa        *csap, *ncsap;
157
158         /*
159          * Return if there's nothing to free
160          */
161         if (csup == (Scsp_csu_msg *)0)
162                 return;
163
164         /*
165          * Free the CSA records
166          */
167         for (csap = csup->csu_csa_rec; csap; csap = ncsap) {
168                 ncsap = csap->next;
169                 SCSP_FREE_CSA(csap);
170         }
171
172         /*
173          * Free the CSU message structure
174          */
175         free(csup);
176 }
177
178
179 /*
180  * Free an SCSP Hello message in  internal format
181  *
182  * Arguments:
183  *      hp      pointer to Hello message
184  *
185  * Returns:
186  *      None
187  *
188  */
189 static void
190 scsp_free_hello(hp)
191         Scsp_hello      *hp;
192 {
193         /*
194          * Return if there's nothing to free
195          */
196         if (hp == (Scsp_hello *)0)
197                 return;
198
199         /*
200          * Free the Hello message structure
201          */
202         free(hp);
203 }
204
205
206 /*
207  * Free an SCSP message in  internal format
208  *
209  * Arguments:
210  *      msg     pointer to input packet
211  *
212  * Returns:
213  *      None
214  *
215  */
216 void
217 scsp_free_msg(msg)
218         Scsp_msg        *msg;
219 {
220         Scsp_ext        *exp, *nexp;
221
222         /*
223          * Return if there's nothing to free
224          */
225         if (msg == (Scsp_msg *)0)
226                 return;
227
228         /*
229          * Free the message body
230          */
231         switch(msg->sc_msg_type) {
232         case SCSP_CA_MSG:
233                 scsp_free_ca(msg->sc_ca);
234                 break;
235         case SCSP_CSU_REQ_MSG:
236         case SCSP_CSU_REPLY_MSG:
237         case SCSP_CSUS_MSG:
238                 scsp_free_csu(msg->sc_csu_msg);
239                 break;
240         case SCSP_HELLO_MSG:
241                 scsp_free_hello(msg->sc_hello);
242                 break;
243         }
244
245         /*
246          * Free any extensions
247          */
248         for (exp = msg->sc_ext; exp; exp = nexp) {
249                 nexp = exp->next;
250                 free(exp);
251         }
252
253         /*
254          * Free the message structure
255          */
256         free(msg);
257 }
258
259
260 /*
261  * Parse a Sender or Receiver ID
262  *
263  * Arguments:
264  *      buff    pointer to ID
265  *      id_len  length of ID
266  *      idp     pointer to structure to receive the ID
267  *
268  * Returns:
269  *      0       input was invalid
270  *      else    length of ID processed
271  *
272  */
273 static int
274 scsp_parse_id(buff, id_len, idp)
275         char    *buff;
276         int     id_len;
277         Scsp_id *idp;
278 {
279         /*
280          * Sanity check
281          */
282         if (!buff ||
283                         id_len == 0 || id_len > SCSP_MAX_ID_LEN ||
284                         !idp) {
285                 return(0);
286         }
287
288         /*
289          * Save the ID length
290          */
291         idp->id_len = id_len;
292
293         /*
294          * Get the ID
295          */
296         bcopy(buff, idp->id, id_len);
297
298         /*
299          * Return the ID length
300          */
301         return(id_len);
302 }
303
304
305 /*
306  * Parse the Mandatory Common Part of an SCSP input packet
307  *
308  * Arguments:
309  *      buff    pointer to mandatory common part
310  *      pdu_len length of input packet
311  *      mcp     pointer to location of MCP in decoded record
312  *
313  * Returns:
314  *      0       input was invalid
315  *      else    length of MCP in message
316  *
317  */
318 static int
319 scsp_parse_mcp(buff, pdu_len, mcp)
320         char            *buff;
321         int             pdu_len;
322         Scsp_mcp        *mcp;
323 {
324         int                     len;
325         u_char                  *idp;
326         struct scsp_nmcp        *smp;
327
328         /*
329          * Get the protocol ID
330          */
331         smp = (struct scsp_nmcp *)buff;
332         mcp->pid = ntohs(smp->sm_pid);
333         if (mcp->pid < SCSP_PROTO_ATMARP ||
334                         mcp->pid > SCSP_PROTO_LNNI) {
335                 /* Protocol ID is invalid */
336                 goto mcp_invalid;
337         }
338
339         /*
340          * Get the server group ID
341          */
342         mcp->sgid = ntohs(smp->sm_sgid);
343
344         /*
345          * Get the flags
346          */
347         mcp->flags = ntohs(smp->sm_flags);
348
349         /*
350          * Get the sender ID and length
351          */
352         idp = (u_char *) ((caddr_t)smp + sizeof(struct scsp_nmcp));
353         len = scsp_parse_id(idp, smp->sm_sid_len, &mcp->sid);
354         if (len == 0) {
355                 goto mcp_invalid;
356          }
357
358         /*
359          * Get the receiver ID and length
360          */
361         idp += len;
362         len = scsp_parse_id(idp, smp->sm_rid_len, &mcp->rid);
363         if (len == 0) {
364                 goto mcp_invalid;
365          }
366
367         /*
368          * Get the record count
369          */
370         mcp->rec_cnt = ntohs(smp->sm_rec_cnt);
371
372         /*
373          * Return the length of data we processed
374          */
375         return(sizeof(struct scsp_nmcp) + smp->sm_sid_len +
376                         smp->sm_rid_len);
377
378 mcp_invalid:
379         return(0);
380 }
381
382
383 /*
384  * Parse an Extension
385  *
386  * Arguments:
387  *      buff    pointer to Extension
388  *      pdu_len length of buffer
389  *      expp    pointer to location to receive pointer to the Extension
390  *
391  * Returns:
392  *      0       input was invalid
393  *      else    length of Extension processed
394  *
395  */
396 static int
397 scsp_parse_ext(buff, pdu_len, expp)
398         char            *buff;
399         int             pdu_len;
400         Scsp_ext        **expp;
401 {
402         int                     len;
403         struct scsp_next        *sep;
404         Scsp_ext                *exp;
405
406         /*
407          * Get memory for the extension
408          */
409         sep = (struct scsp_next *)buff;
410         len = sizeof(Scsp_ext) + ntohs(sep->se_len);
411         exp = calloc(1, len);
412         if (exp == NULL)
413                 goto ext_invalid;
414
415         /*
416          * Get the type
417          */
418         exp->type = ntohs(sep->se_type);
419
420         /*
421          * Get the length
422          */
423         exp->len = ntohs(sep->se_len);
424
425         /*
426          * Get the value
427          */
428         if (exp->len > 0) {
429                 bcopy((caddr_t)sep + sizeof(struct scsp_next),
430                                 (caddr_t)exp + sizeof(Scsp_ext),
431                                 exp->len);
432         }
433
434         /*
435          * Save a pointer to the extension and return the
436          * number of bytes processed
437          */
438         *expp = exp;
439         return(sizeof(struct scsp_next) + exp->len);
440
441 ext_invalid:
442         if (exp) {
443                 free(exp);
444         }
445         return(0);
446 }
447
448
449 /*
450  * Parse a Cache State Advertisement or Cache State Advertisement
451  * Summary record
452  *
453  * Arguments:
454  *      buff    pointer to CSA or CSAS record
455  *      pdu_len length of input packet
456  *      csapp   pointer to location to put pointer to CSA or CSAS
457  *
458  * Returns:
459  *      0       input was invalid
460  *      else    length of record processed
461  *
462  */
463 static int
464 scsp_parse_csa(buff, pdu_len, csapp)
465         char            *buff;
466         int             pdu_len;
467         Scsp_csa        **csapp;
468 {
469         int                     len;
470         char                    *idp;
471         struct scsp_ncsa        *scp;
472         Scsp_csa                *csap = NULL;
473
474         /*
475          * Check the record length
476          */
477         scp = (struct scsp_ncsa *)buff;
478         if (ntohs(scp->scs_len) < (sizeof(struct scsp_ncsa) +
479                         scp->scs_ck_len + scp->scs_oid_len)) {
480                 goto csa_invalid;
481         }
482
483         /*
484          * Get memory for the returned structure
485          */
486         len = sizeof(Scsp_csa) + ntohs(scp->scs_len) -
487                         sizeof(struct scsp_ncsa) - scp->scs_ck_len -
488                         scp->scs_oid_len;
489         csap = calloc(1, len);
490         if (csap == NULL)
491                 goto csa_invalid;
492
493         /*
494          * Get the hop count
495          */
496         csap->hops = ntohs(scp->scs_hop_cnt);
497
498         /*
499          * Set the null flag
500          */
501         csap->null = (ntohs(scp->scs_nfill) & SCSP_CSAS_NULL) != 0;
502
503         /*
504          * Get the sequence number
505          */
506         csap->seq = get_long((u_char *)&scp->scs_seq);
507
508         /*
509          * Get the cache key
510          */
511         if (scp->scs_ck_len == 0 ||
512                         scp->scs_ck_len > SCSP_MAX_KEY_LEN) {
513                 goto csa_invalid;
514         }
515         csap->key.key_len = scp->scs_ck_len;
516         idp = (char *) ((caddr_t)scp + sizeof(struct scsp_ncsa));
517         bcopy(idp, csap->key.key, scp->scs_ck_len);
518
519         /*
520          * Get the originator ID
521          */
522         idp += scp->scs_ck_len;
523         len = scsp_parse_id(idp, scp->scs_oid_len, &csap->oid);
524         if (len == 0) {
525                 goto csa_invalid;
526         }
527
528         /*
529          * Get the protocol-specific data, if present
530          */
531         len = ntohs(scp->scs_len) - (sizeof(struct scsp_ncsa) +
532                         scp->scs_ck_len + scp->scs_oid_len);
533         if (len > 0) {
534                 idp += scp->scs_oid_len;
535                 len = scsp_parse_atmarp(idp, len, &csap->atmarp_data);
536                 if (len == 0)
537                         goto csa_invalid;
538         }
539
540         /*
541          * Set a pointer to the MCP and return the length
542          * of data we processed
543          */
544         *csapp = csap;
545         return(ntohs(scp->scs_len));
546
547 csa_invalid:
548         if (csap)
549                 SCSP_FREE_CSA(csap);
550         return(0);
551 }
552
553
554 /*
555  * Parse a Cache Alignment message
556  *
557  * Arguments:
558  *      buff    pointer to start of CA in message
559  *      pdu_len length of input packet
560  *      capp    pointer to location to put pointer to CA message
561  *
562  * Returns:
563  *      0       input was invalid
564  *      else    length of CA message processed
565  *
566  */
567 static int
568 scsp_parse_ca(buff, pdu_len, capp)
569         char    *buff;
570         int     pdu_len;
571         Scsp_ca **capp;
572 {
573         int             i, len, proc_len;
574         struct scsp_nca *scap;
575         Scsp_ca         *cap;
576         Scsp_csa        **csapp;
577
578         /*
579          * Get memory for the returned structure
580          */
581         scap = (struct scsp_nca *)buff;
582         cap = calloc(1, sizeof(Scsp_ca));
583         if (cap == NULL)
584                 goto ca_invalid;
585
586         /*
587          * Get the sequence number
588          */
589         cap->ca_seq = get_long((u_char *)&scap->sca_seq);
590         proc_len = sizeof(scap->sca_seq);
591         buff += sizeof(scap->sca_seq);
592
593         /*
594          * Process the mandatory common part of the message
595          */
596         len = scsp_parse_mcp(buff,
597                         pdu_len - proc_len,
598                         &cap->ca_mcp);
599         if (len == 0)
600                 goto ca_invalid;
601         buff += len;
602         proc_len += len;
603
604         /*
605          * Set the flags
606          */
607         cap->ca_m = (cap->ca_mcp.flags & SCSP_CA_M) != 0;
608         cap->ca_i = (cap->ca_mcp.flags & SCSP_CA_I) != 0;
609         cap->ca_o = (cap->ca_mcp.flags & SCSP_CA_O) != 0;
610
611         /*
612          * Get the CSAS records from the message
613          */
614         for (i = 0, csapp = &cap->ca_csa_rec; i < cap->ca_mcp.rec_cnt;
615                         i++, csapp = &(*csapp)->next) {
616                 len = scsp_parse_csa(buff, pdu_len - proc_len, csapp);
617                 buff += len;
618                 proc_len += len;
619         }
620
621         /*
622          * Set the address of the CA message and
623          * return the length of processed data
624          */
625         *capp = cap;
626         return(proc_len);
627
628 ca_invalid:
629         if (cap)
630                 scsp_free_ca(cap);
631         return(0);
632 }
633
634
635 /*
636  * Parse the ATMARP-specific part of a CSA record
637  *
638  * Arguments:
639  *      buff    pointer to ATMARP part of CSU message
640  *      pdu_len length of data to process
641  *      acspp   pointer to location to put pointer to CSU message
642  *
643  * Returns:
644  *      0       input was invalid
645  *      else    length of CSU Req message processed
646  *
647  */
648 static int
649 scsp_parse_atmarp(buff, pdu_len, acspp)
650         char            *buff;
651         int             pdu_len;
652         Scsp_atmarp_csa **acspp;
653 {
654         int                     len, proc_len;
655         struct scsp_atmarp_ncsa *sacp;
656         Scsp_atmarp_csa         *acsp = NULL;
657
658         /*
659          * Initial packet verification
660          */
661         sacp = (struct scsp_atmarp_ncsa *)buff;
662         if ((sacp->sa_hrd != ntohs(ARP_ATMFORUM)) ||
663                         (sacp->sa_pro != ntohs(ETHERTYPE_IP)))
664                 goto acs_invalid;
665
666         /*
667          * Get memory for the returned structure
668          */
669         acsp = calloc(1, sizeof(Scsp_atmarp_csa));
670         if (acsp == NULL)
671                 goto acs_invalid;
672
673         /*
674          * Get state code
675          */
676         acsp->sa_state = sacp->sa_state;
677         proc_len = sizeof(struct scsp_atmarp_ncsa);
678
679         /*
680          * Verify/gather source ATM address
681          */
682         acsp->sa_sha.address_format = T_ATM_ABSENT;
683         acsp->sa_sha.address_length = 0;
684         if ((len = (sacp->sa_shtl & ARP_TL_LMASK)) != 0) {
685                 if (sacp->sa_shtl & ARP_TL_E164) {
686                         if (len > sizeof(Atm_addr_e164))
687                                 goto acs_invalid;
688                         acsp->sa_sha.address_format = T_ATM_E164_ADDR;
689                 } else {
690                         if (len != sizeof(Atm_addr_nsap))
691                                 goto acs_invalid;
692                         acsp->sa_sha.address_format = T_ATM_ENDSYS_ADDR;
693                 }
694                 acsp->sa_sha.address_length = len;
695                 if (pdu_len < proc_len + len)
696                         goto acs_invalid;
697                 bcopy(&buff[proc_len], (char *)acsp->sa_sha.address,
698                                 len);
699                 proc_len += len;
700         }
701
702         /*
703          * Verify/gather source ATM subaddress
704          */
705         acsp->sa_ssa.address_format = T_ATM_ABSENT;
706         acsp->sa_ssa.address_length = 0;
707         if ((len = (sacp->sa_sstl & ARP_TL_LMASK)) != 0) {
708                 if (((sacp->sa_sstl & ARP_TL_TMASK) != ARP_TL_NSAPA) ||
709                                 (len != sizeof(Atm_addr_nsap)))
710                         goto acs_invalid;
711                 acsp->sa_ssa.address_format = T_ATM_ENDSYS_ADDR;
712                 acsp->sa_ssa.address_length = len;
713                 if (pdu_len < proc_len + len)
714                         goto acs_invalid;
715                 bcopy(&buff[proc_len], (char *)acsp->sa_ssa.address,
716                                 len);
717                 proc_len += len;
718         }
719
720         /*
721          * Verify/gather source IP address
722          */
723         if ((len = sacp->sa_spln) != 0) {
724                 if (len != sizeof(struct in_addr))
725                         goto acs_invalid;
726                 if (pdu_len < proc_len + len)
727                         goto acs_invalid;
728                 bcopy(&buff[proc_len], (char *)&acsp->sa_spa, len);
729                 proc_len += len;
730         } else {
731                 acsp->sa_spa.s_addr = 0;
732         }
733
734         /*
735          * Verify/gather target ATM address
736          */
737         acsp->sa_tha.address_format = T_ATM_ABSENT;
738         acsp->sa_tha.address_length = 0;
739         if ((len = (sacp->sa_thtl & ARP_TL_LMASK)) != 0) {
740                 if (sacp->sa_thtl & ARP_TL_E164) {
741                         if (len > sizeof(Atm_addr_e164))
742                                 goto acs_invalid;
743                         acsp->sa_tha.address_format = T_ATM_E164_ADDR;
744                 } else {
745                         if (len != sizeof(Atm_addr_nsap))
746                                 goto acs_invalid;
747                         acsp->sa_tha.address_format = T_ATM_ENDSYS_ADDR;
748                 }
749                 acsp->sa_tha.address_length = len;
750                 if (pdu_len < proc_len + len)
751                         goto acs_invalid;
752                 bcopy(&buff[proc_len], (char *)acsp->sa_tha.address,
753                                 len);
754                 proc_len += len;
755         }
756
757         /*
758          * Verify/gather target ATM subaddress
759          */
760         acsp->sa_tsa.address_format = T_ATM_ABSENT;
761         acsp->sa_tsa.address_length = 0;
762         if ((len = (sacp->sa_tstl & ARP_TL_LMASK)) != 0) {
763                 if (((sacp->sa_tstl & ARP_TL_TMASK) != ARP_TL_NSAPA) ||
764                                 (len != sizeof(Atm_addr_nsap)))
765                         goto acs_invalid;
766                 acsp->sa_tsa.address_format = T_ATM_ENDSYS_ADDR;
767                 acsp->sa_tsa.address_length = len;
768                 if (pdu_len < proc_len + len)
769                         goto acs_invalid;
770                 bcopy(&buff[proc_len], (char *)acsp->sa_tsa.address,
771                                 len);
772                 proc_len += len;
773         }
774
775         /*
776          * Verify/gather target IP address
777          */
778         if ((len = sacp->sa_tpln) != 0) {
779                 if (len != sizeof(struct in_addr))
780                         goto acs_invalid;
781                 if (pdu_len < proc_len + len)
782                         goto acs_invalid;
783                 bcopy(&buff[proc_len], (char *)&acsp->sa_tpa, len);
784                 proc_len += len;
785         } else {
786                 acsp->sa_tpa.s_addr = 0;
787         }
788
789         /*
790          * Verify packet length
791          */
792         if (proc_len != pdu_len)
793                 goto acs_invalid;
794
795         *acspp = acsp;
796         return(proc_len);
797
798 acs_invalid:
799         if (acsp)
800                 free(acsp);
801         return(0);
802 }
803
804
805 /*
806  * Parse a Cache State Update Request, Cache State Update Reply, or
807  * Cache State Update Solicit message.  These all have the same format,
808  * a Mandatory Common Part followed by a number of CSA or CSAS records.
809  *
810  * Arguments:
811  *      buff    pointer to start of CSU message
812  *      pdu_len length of input packet
813  *      csupp   pointer to location to put pointer to CSU message
814  *
815  * Returns:
816  *      0       input was invalid
817  *      else    length of CSU Req message processed
818  *
819  */
820 static int
821 scsp_parse_csu(buff, pdu_len, csupp)
822         char            *buff;
823         int             pdu_len;
824         Scsp_csu_msg    **csupp;
825 {
826         int                     i, len, proc_len;
827         Scsp_csu_msg            *csup;
828         Scsp_csa                **csapp;
829
830         /*
831          * Get memory for the returned structure
832          */
833         csup = calloc(1, sizeof(Scsp_csu_msg));
834         if (csup == NULL)
835                 goto csu_invalid;
836
837         /*
838          * Process the mandatory common part of the message
839          */
840         len = scsp_parse_mcp(buff, pdu_len, &csup->csu_mcp);
841         if (len == 0)
842                 goto csu_invalid;
843         buff += len;
844         proc_len = len;
845
846         /*
847          * Get the CSAS records from the message
848          */
849         for (i = 0, csapp = &csup->csu_csa_rec;
850                         i < csup->csu_mcp.rec_cnt;
851                         i++, csapp = &(*csapp)->next) {
852                 len = scsp_parse_csa(buff, pdu_len - proc_len, csapp);
853                 buff += len;
854                 proc_len += len;
855         }
856
857         /*
858          * Set the address of the CSU Req message and
859          * return the length of processed data
860          */
861         *csupp = csup;
862         return(proc_len);
863
864 csu_invalid:
865         if (csup)
866                 scsp_free_csu(csup);
867         return(0);
868 }
869
870
871 /*
872  * Parse a Hello message
873  *
874  * Arguments:
875  *      buff    pointer to start of Hello in message
876  *      pdu_len length of input packet
877  *      hpp     pointer to location to put pointer to Hello message
878  *
879  * Returns:
880  *      0       input was invalid
881  *      else    length of Hello message processed
882  *
883  */
884 static int
885 scsp_parse_hello(buff, pdu_len, hpp)
886         char            *buff;
887         int             pdu_len;
888         Scsp_hello      **hpp;
889 {
890         int                     i, len, proc_len;
891         struct scsp_nhello      *shp = (struct scsp_nhello *)buff;
892         Scsp_hello              *hp;
893         Scsp_id                 *idp;
894         Scsp_id                 **ridpp;
895
896         /*
897          * Get memory for the returned structure
898          */
899         hp = calloc(1, sizeof(Scsp_hello));
900         if (hp == NULL)
901                 goto hello_invalid;
902
903         /*
904          * Get the hello interval
905          */
906         hp->hello_int = ntohs(shp->sch_hi);
907
908         /*
909          * Get the dead factor
910          */
911         hp->dead_factor = ntohs(shp->sch_df);
912
913         /*
914          * Get the family ID
915          */
916         hp->family_id = ntohs(shp->sch_fid);
917
918         /*
919          * Process the mandatory common part of the message
920          */
921         proc_len = sizeof(struct scsp_nhello) -
922                         sizeof(struct scsp_nmcp);
923         buff += proc_len;
924         len = scsp_parse_mcp(buff, pdu_len - proc_len,
925                         &hp->hello_mcp);
926         if (len == 0)
927                 goto hello_invalid;
928         buff += len;
929         proc_len += len;
930
931         /*
932          * Get additional receiver ID records from the message
933          */
934         for (i = 0, ridpp = &hp->hello_mcp.rid.next;
935                         i < hp->hello_mcp.rec_cnt;
936                         i++, ridpp = &idp->next) {
937                 idp = calloc(1, sizeof(Scsp_id));
938                 if (idp == NULL)
939                         goto hello_invalid;
940                 len = scsp_parse_id(buff,
941                                 hp->hello_mcp.rid.id_len,
942                                 idp);
943                 if (len == 0) {
944                         free(idp);
945                         goto hello_invalid;
946                 }
947                 buff += len;
948                 proc_len += len;
949                 *ridpp = idp;
950         }
951
952         /*
953          * Set the address of the CA message and
954          * return the length of processed data
955          */
956         *hpp = hp;
957         return(proc_len);
958
959 hello_invalid:
960         if (hp)
961                 scsp_free_hello(hp);
962         return(0);
963 }
964
965
966 /*
967  * Parse an SCSP input packet
968  *
969  * Arguments:
970  *      buff    pointer to input packet
971  *      pdu_len length of input packet
972  *
973  * Returns:
974  *      NULL    input packet was invalid
975  *      else    pointer to packet in internal format
976  *
977  */
978 Scsp_msg *
979 scsp_parse_msg(buff, pdu_len)
980         char                    *buff;
981         int                     pdu_len;
982 {
983         int                     ext_off, len, plen;
984         struct scsp_nhdr        *shp;
985         Scsp_msg                *msg = (Scsp_msg *)0;
986         Scsp_ext                **expp;
987
988         /*
989          * Check the message checksum
990          */
991         if (ip_checksum(buff, pdu_len) != 0) {
992                 /*
993                  * Checksum was bad--discard the message
994                  */
995                 goto ignore;
996         }
997
998         /*
999          * Allocate storage for the message
1000          */
1001         msg = calloc(1, sizeof(Scsp_msg));
1002         if (msg == NULL)
1003                 goto ignore;
1004
1005         /*
1006          * Decode the fixed header
1007          *
1008          * Check the version
1009          */
1010         shp = (struct scsp_nhdr *)buff;
1011         if (shp->sh_ver != SCSP_VER_1)
1012                 goto ignore;
1013
1014         /*
1015          * Get the message type
1016          */
1017         msg->sc_msg_type = shp->sh_type;
1018
1019         /*
1020          * Get and check the length
1021          */
1022         len = ntohs(shp->sh_len);
1023         if (len != pdu_len)
1024                 goto ignore;
1025
1026         /*
1027          * Get the extension offset
1028          */
1029         ext_off = ntohs(shp->sh_ext_off);
1030
1031         /*
1032          * Decode the body of the message, depending on the type
1033          */
1034         buff += sizeof(struct scsp_nhdr);
1035         len -= sizeof(struct scsp_nhdr);
1036         switch(msg->sc_msg_type) {
1037         case SCSP_CA_MSG:
1038                 plen = scsp_parse_ca(buff, len, &msg->sc_ca);
1039                 break;
1040         case SCSP_CSU_REQ_MSG:
1041         case SCSP_CSU_REPLY_MSG:
1042         case SCSP_CSUS_MSG:
1043                 plen = scsp_parse_csu(buff, len, &msg->sc_csu_msg);
1044                 break;
1045         case SCSP_HELLO_MSG:
1046                 plen = scsp_parse_hello(buff, len, &msg->sc_hello);
1047                 break;
1048         default:
1049                 goto ignore;
1050         }
1051         if (plen == 0) {
1052                 goto ignore;
1053         }
1054         buff += plen;
1055         len -= plen;
1056
1057         /*
1058          * Decode any extensions
1059          */
1060         if (ext_off != 0) {
1061                 for (expp = &msg->sc_ext; len > 0;
1062                                 expp = &(*expp)->next) {
1063                         plen = scsp_parse_ext(buff, len, expp);
1064                         if (plen == 0) {
1065                                 goto ignore;
1066                         }
1067                         buff += plen;
1068                         len -= plen;
1069                 }
1070         }
1071
1072         /*
1073          * Make sure we handled the whole message
1074          */
1075         if (len != 0) {
1076                 goto ignore;
1077         }
1078
1079         /*
1080          * Return the address of the SCSP message in internal format
1081          */
1082         return(msg);
1083
1084 ignore:
1085         if (msg)
1086                 scsp_free_msg(msg);
1087         return(Scsp_msg *)0;
1088 }