Initial import from FreeBSD RELENG_4:
[dragonfly.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: src/usr.sbin/atm/scspd/scsp_input.c,v 1.3 1999/08/28 01:15:33 peter Exp $
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: src/usr.sbin/atm/scspd/scsp_input.c,v 1.3 1999/08/28 01:15:33 peter Exp $");
65 #endif
66
67
68 static int scsp_parse_atmarp __P((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         UM_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         UM_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         UM_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                 UM_FREE(exp);
251         }
252
253         /*
254          * Free the message structure
255          */
256         UM_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         UM_COPY(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 = (Scsp_ext *)UM_ALLOC(len);
412         if (!exp) {
413                 goto ext_invalid;
414         }
415         UM_ZERO(exp, len);
416
417         /*
418          * Get the type
419          */
420         exp->type = ntohs(sep->se_type);
421
422         /*
423          * Get the length
424          */
425         exp->len = ntohs(sep->se_len);
426
427         /*
428          * Get the value
429          */
430         if (exp->len > 0) {
431                 UM_COPY((caddr_t)sep + sizeof(struct scsp_next),
432                                 (caddr_t)exp + sizeof(Scsp_ext),
433                                 exp->len);
434         }
435
436         /*
437          * Save a pointer to the extension and return the
438          * number of bytes processed
439          */
440         *expp = exp;
441         return(sizeof(struct scsp_next) + exp->len);
442
443 ext_invalid:
444         if (exp) {
445                 UM_FREE(exp);
446         }
447         return(0);
448 }
449
450
451 /*
452  * Parse a Cache State Advertisement or Cache State Advertisement
453  * Summary record
454  *
455  * Arguments:
456  *      buff    pointer to CSA or CSAS record
457  *      pdu_len length of input packet
458  *      csapp   pointer to location to put pointer to CSA or CSAS
459  *
460  * Returns:
461  *      0       input was invalid
462  *      else    length of record processed
463  *
464  */
465 static int
466 scsp_parse_csa(buff, pdu_len, csapp)
467         char            *buff;
468         int             pdu_len;
469         Scsp_csa        **csapp;
470 {
471         int                     len;
472         char                    *idp;
473         struct scsp_ncsa        *scp;
474         Scsp_csa                *csap = NULL;
475
476         /*
477          * Check the record length
478          */
479         scp = (struct scsp_ncsa *)buff;
480         if (ntohs(scp->scs_len) < (sizeof(struct scsp_ncsa) +
481                         scp->scs_ck_len + scp->scs_oid_len)) {
482                 goto csa_invalid;
483         }
484
485         /*
486          * Get memory for the returned structure
487          */
488         len = sizeof(Scsp_csa) + ntohs(scp->scs_len) -
489                         sizeof(struct scsp_ncsa) - scp->scs_ck_len -
490                         scp->scs_oid_len;
491         csap = (Scsp_csa *)UM_ALLOC(len);
492         if (!csap) {
493                 goto csa_invalid;
494         }
495         UM_ZERO(csap, len);
496
497         /*
498          * Get the hop count
499          */
500         csap->hops = ntohs(scp->scs_hop_cnt);
501
502         /*
503          * Set the null flag
504          */
505         csap->null = (ntohs(scp->scs_nfill) & SCSP_CSAS_NULL) != 0;
506
507         /*
508          * Get the sequence number
509          */
510         csap->seq = get_long((u_char *)&scp->scs_seq);
511
512         /*
513          * Get the cache key
514          */
515         if (scp->scs_ck_len == 0 ||
516                         scp->scs_ck_len > SCSP_MAX_KEY_LEN) {
517                 goto csa_invalid;
518         }
519         csap->key.key_len = scp->scs_ck_len;
520         idp = (char *) ((caddr_t)scp + sizeof(struct scsp_ncsa));
521         UM_COPY(idp, csap->key.key, scp->scs_ck_len);
522
523         /*
524          * Get the originator ID
525          */
526         idp += scp->scs_ck_len;
527         len = scsp_parse_id(idp, scp->scs_oid_len, &csap->oid);
528         if (len == 0) {
529                 goto csa_invalid;
530         }
531
532         /*
533          * Get the protocol-specific data, if present
534          */
535         len = ntohs(scp->scs_len) - (sizeof(struct scsp_ncsa) +
536                         scp->scs_ck_len + scp->scs_oid_len);
537         if (len > 0) {
538                 idp += scp->scs_oid_len;
539                 len = scsp_parse_atmarp(idp, len, &csap->atmarp_data);
540                 if (len == 0)
541                         goto csa_invalid;
542         }
543
544         /*
545          * Set a pointer to the MCP and return the length
546          * of data we processed
547          */
548         *csapp = csap;
549         return(ntohs(scp->scs_len));
550
551 csa_invalid:
552         if (csap)
553                 SCSP_FREE_CSA(csap);
554         return(0);
555 }
556
557
558 /*
559  * Parse a Cache Alignment message
560  *
561  * Arguments:
562  *      buff    pointer to start of CA in message
563  *      pdu_len length of input packet
564  *      capp    pointer to location to put pointer to CA message
565  *
566  * Returns:
567  *      0       input was invalid
568  *      else    length of CA message processed
569  *
570  */
571 static int
572 scsp_parse_ca(buff, pdu_len, capp)
573         char    *buff;
574         int     pdu_len;
575         Scsp_ca **capp;
576 {
577         int             i, len, proc_len;
578         struct scsp_nca *scap;
579         Scsp_ca         *cap;
580         Scsp_csa        **csapp;
581
582         /*
583          * Get memory for the returned structure
584          */
585         scap = (struct scsp_nca *)buff;
586         cap = (Scsp_ca *)UM_ALLOC(sizeof(Scsp_ca));
587         if (!cap) {
588                 goto ca_invalid;
589         }
590         UM_ZERO(cap, sizeof(Scsp_ca));
591
592         /*
593          * Get the sequence number
594          */
595         cap->ca_seq = get_long((u_char *)&scap->sca_seq);
596         proc_len = sizeof(scap->sca_seq);
597         buff += sizeof(scap->sca_seq);
598
599         /*
600          * Process the mandatory common part of the message
601          */
602         len = scsp_parse_mcp(buff,
603                         pdu_len - proc_len,
604                         &cap->ca_mcp);
605         if (len == 0)
606                 goto ca_invalid;
607         buff += len;
608         proc_len += len;
609
610         /*
611          * Set the flags
612          */
613         cap->ca_m = (cap->ca_mcp.flags & SCSP_CA_M) != 0;
614         cap->ca_i = (cap->ca_mcp.flags & SCSP_CA_I) != 0;
615         cap->ca_o = (cap->ca_mcp.flags & SCSP_CA_O) != 0;
616
617         /*
618          * Get the CSAS records from the message
619          */
620         for (i = 0, csapp = &cap->ca_csa_rec; i < cap->ca_mcp.rec_cnt;
621                         i++, csapp = &(*csapp)->next) {
622                 len = scsp_parse_csa(buff, pdu_len - proc_len, csapp);
623                 buff += len;
624                 proc_len += len;
625         }
626
627         /*
628          * Set the address of the CA message and
629          * return the length of processed data
630          */
631         *capp = cap;
632         return(proc_len);
633
634 ca_invalid:
635         if (cap)
636                 scsp_free_ca(cap);
637         return(0);
638 }
639
640
641 /*
642  * Parse the ATMARP-specific part of a CSA record
643  *
644  * Arguments:
645  *      buff    pointer to ATMARP part of CSU message
646  *      pdu_len length of data to process
647  *      acspp   pointer to location to put pointer to CSU message
648  *
649  * Returns:
650  *      0       input was invalid
651  *      else    length of CSU Req message processed
652  *
653  */
654 static int
655 scsp_parse_atmarp(buff, pdu_len, acspp)
656         char            *buff;
657         int             pdu_len;
658         Scsp_atmarp_csa **acspp;
659 {
660         int                     len, proc_len;
661         struct scsp_atmarp_ncsa *sacp;
662         Scsp_atmarp_csa         *acsp = NULL;
663
664         /*
665          * Initial packet verification
666          */
667         sacp = (struct scsp_atmarp_ncsa *)buff;
668         if ((sacp->sa_hrd != ntohs(ARP_ATMFORUM)) ||
669                         (sacp->sa_pro != ntohs(ETHERTYPE_IP)))
670                 goto acs_invalid;
671
672         /*
673          * Get memory for the returned structure
674          */
675         acsp = (Scsp_atmarp_csa *)UM_ALLOC(sizeof(Scsp_atmarp_csa));
676         if (!acsp) {
677                 goto acs_invalid;
678         }
679         UM_ZERO(acsp, sizeof(Scsp_atmarp_csa));
680
681         /*
682          * Get state code
683          */
684         acsp->sa_state = sacp->sa_state;
685         proc_len = sizeof(struct scsp_atmarp_ncsa);
686
687         /*
688          * Verify/gather source ATM address
689          */
690         acsp->sa_sha.address_format = T_ATM_ABSENT;
691         acsp->sa_sha.address_length = 0;
692         if ((len = (sacp->sa_shtl & ARP_TL_LMASK)) != 0) {
693                 if (sacp->sa_shtl & ARP_TL_E164) {
694                         if (len > sizeof(Atm_addr_e164))
695                                 goto acs_invalid;
696                         acsp->sa_sha.address_format = T_ATM_E164_ADDR;
697                 } else {
698                         if (len != sizeof(Atm_addr_nsap))
699                                 goto acs_invalid;
700                         acsp->sa_sha.address_format = T_ATM_ENDSYS_ADDR;
701                 }
702                 acsp->sa_sha.address_length = len;
703                 if (pdu_len < proc_len + len)
704                         goto acs_invalid;
705                 UM_COPY(&buff[proc_len], (char *)acsp->sa_sha.address,
706                                 len);
707                 proc_len += len;
708         }
709
710         /*
711          * Verify/gather source ATM subaddress
712          */
713         acsp->sa_ssa.address_format = T_ATM_ABSENT;
714         acsp->sa_ssa.address_length = 0;
715         if ((len = (sacp->sa_sstl & ARP_TL_LMASK)) != 0) {
716                 if (((sacp->sa_sstl & ARP_TL_TMASK) != ARP_TL_NSAPA) ||
717                                 (len != sizeof(Atm_addr_nsap)))
718                         goto acs_invalid;
719                 acsp->sa_ssa.address_format = T_ATM_ENDSYS_ADDR;
720                 acsp->sa_ssa.address_length = len;
721                 if (pdu_len < proc_len + len)
722                         goto acs_invalid;
723                 UM_COPY(&buff[proc_len], (char *)acsp->sa_ssa.address,
724                                 len);
725                 proc_len += len;
726         }
727
728         /*
729          * Verify/gather source IP address
730          */
731         if ((len = sacp->sa_spln) != 0) {
732                 if (len != sizeof(struct in_addr))
733                         goto acs_invalid;
734                 if (pdu_len < proc_len + len)
735                         goto acs_invalid;
736                 UM_COPY(&buff[proc_len], (char *)&acsp->sa_spa, len);
737                 proc_len += len;
738         } else {
739                 acsp->sa_spa.s_addr = 0;
740         }
741
742         /*
743          * Verify/gather target ATM address
744          */
745         acsp->sa_tha.address_format = T_ATM_ABSENT;
746         acsp->sa_tha.address_length = 0;
747         if ((len = (sacp->sa_thtl & ARP_TL_LMASK)) != 0) {
748                 if (sacp->sa_thtl & ARP_TL_E164) {
749                         if (len > sizeof(Atm_addr_e164))
750                                 goto acs_invalid;
751                         acsp->sa_tha.address_format = T_ATM_E164_ADDR;
752                 } else {
753                         if (len != sizeof(Atm_addr_nsap))
754                                 goto acs_invalid;
755                         acsp->sa_tha.address_format = T_ATM_ENDSYS_ADDR;
756                 }
757                 acsp->sa_tha.address_length = len;
758                 if (pdu_len < proc_len + len)
759                         goto acs_invalid;
760                 UM_COPY(&buff[proc_len], (char *)acsp->sa_tha.address,
761                                 len);
762                 proc_len += len;
763         }
764
765         /*
766          * Verify/gather target ATM subaddress
767          */
768         acsp->sa_tsa.address_format = T_ATM_ABSENT;
769         acsp->sa_tsa.address_length = 0;
770         if ((len = (sacp->sa_tstl & ARP_TL_LMASK)) != 0) {
771                 if (((sacp->sa_tstl & ARP_TL_TMASK) != ARP_TL_NSAPA) ||
772                                 (len != sizeof(Atm_addr_nsap)))
773                         goto acs_invalid;
774                 acsp->sa_tsa.address_format = T_ATM_ENDSYS_ADDR;
775                 acsp->sa_tsa.address_length = len;
776                 if (pdu_len < proc_len + len)
777                         goto acs_invalid;
778                 UM_COPY(&buff[proc_len], (char *)acsp->sa_tsa.address,
779                                 len);
780                 proc_len += len;
781         }
782
783         /*
784          * Verify/gather target IP address
785          */
786         if ((len = sacp->sa_tpln) != 0) {
787                 if (len != sizeof(struct in_addr))
788                         goto acs_invalid;
789                 if (pdu_len < proc_len + len)
790                         goto acs_invalid;
791                 UM_COPY(&buff[proc_len], (char *)&acsp->sa_tpa, len);
792                 proc_len += len;
793         } else {
794                 acsp->sa_tpa.s_addr = 0;
795         }
796
797         /*
798          * Verify packet length
799          */
800         if (proc_len != pdu_len)
801                 goto acs_invalid;
802
803         *acspp = acsp;
804         return(proc_len);
805
806 acs_invalid:
807         if (acsp)
808                 UM_FREE(acsp);
809         return(0);
810 }
811
812
813 /*
814  * Parse a Cache State Update Request, Cache State Update Reply, or
815  * Cache State Update Solicit message.  These all have the same format,
816  * a Mandatory Common Part followed by a number of CSA or CSAS records.
817  *
818  * Arguments:
819  *      buff    pointer to start of CSU message
820  *      pdu_len length of input packet
821  *      csupp   pointer to location to put pointer to CSU message
822  *
823  * Returns:
824  *      0       input was invalid
825  *      else    length of CSU Req message processed
826  *
827  */
828 static int
829 scsp_parse_csu(buff, pdu_len, csupp)
830         char            *buff;
831         int             pdu_len;
832         Scsp_csu_msg    **csupp;
833 {
834         int                     i, len, proc_len;
835         Scsp_csu_msg            *csup;
836         Scsp_csa                **csapp;
837
838         /*
839          * Get memory for the returned structure
840          */
841         csup = (Scsp_csu_msg *)UM_ALLOC(sizeof(Scsp_csu_msg));
842         if (!csup) {
843                 goto csu_invalid;
844         }
845         UM_ZERO(csup, sizeof(Scsp_csu_msg));
846
847         /*
848          * Process the mandatory common part of the message
849          */
850         len = scsp_parse_mcp(buff, pdu_len, &csup->csu_mcp);
851         if (len == 0)
852                 goto csu_invalid;
853         buff += len;
854         proc_len = len;
855
856         /*
857          * Get the CSAS records from the message
858          */
859         for (i = 0, csapp = &csup->csu_csa_rec;
860                         i < csup->csu_mcp.rec_cnt;
861                         i++, csapp = &(*csapp)->next) {
862                 len = scsp_parse_csa(buff, pdu_len - proc_len, csapp);
863                 buff += len;
864                 proc_len += len;
865         }
866
867         /*
868          * Set the address of the CSU Req message and
869          * return the length of processed data
870          */
871         *csupp = csup;
872         return(proc_len);
873
874 csu_invalid:
875         if (csup)
876                 scsp_free_csu(csup);
877         return(0);
878 }
879
880
881 /*
882  * Parse a Hello message
883  *
884  * Arguments:
885  *      buff    pointer to start of Hello in message
886  *      pdu_len length of input packet
887  *      hpp     pointer to location to put pointer to Hello message
888  *
889  * Returns:
890  *      0       input was invalid
891  *      else    length of Hello message processed
892  *
893  */
894 static int
895 scsp_parse_hello(buff, pdu_len, hpp)
896         char            *buff;
897         int             pdu_len;
898         Scsp_hello      **hpp;
899 {
900         int                     i, len, proc_len;
901         struct scsp_nhello      *shp = (struct scsp_nhello *)buff;
902         Scsp_hello              *hp;
903         Scsp_id                 *idp;
904         Scsp_id                 **ridpp;
905
906         /*
907          * Get memory for the returned structure
908          */
909         hp = (Scsp_hello *)UM_ALLOC(sizeof(Scsp_hello));
910         if (!hp) {
911                 goto hello_invalid;
912         }
913         UM_ZERO(hp, sizeof(Scsp_hello));
914
915         /*
916          * Get the hello interval
917          */
918         hp->hello_int = ntohs(shp->sch_hi);
919
920         /*
921          * Get the dead factor
922          */
923         hp->dead_factor = ntohs(shp->sch_df);
924
925         /*
926          * Get the family ID
927          */
928         hp->family_id = ntohs(shp->sch_fid);
929
930         /*
931          * Process the mandatory common part of the message
932          */
933         proc_len = sizeof(struct scsp_nhello) -
934                         sizeof(struct scsp_nmcp);
935         buff += proc_len;
936         len = scsp_parse_mcp(buff, pdu_len - proc_len,
937                         &hp->hello_mcp);
938         if (len == 0)
939                 goto hello_invalid;
940         buff += len;
941         proc_len += len;
942
943         /*
944          * Get additional receiver ID records from the message
945          */
946         for (i = 0, ridpp = &hp->hello_mcp.rid.next;
947                         i < hp->hello_mcp.rec_cnt;
948                         i++, ridpp = &idp->next) {
949                 idp = (Scsp_id *)UM_ALLOC(sizeof(Scsp_id));
950                 if (!idp) {
951                         goto hello_invalid;
952                 }
953                 UM_ZERO(idp, sizeof(Scsp_id));
954                 len = scsp_parse_id(buff,
955                                 hp->hello_mcp.rid.id_len,
956                                 idp);
957                 if (len == 0) {
958                         UM_FREE(idp);
959                         goto hello_invalid;
960                 }
961                 buff += len;
962                 proc_len += len;
963                 *ridpp = idp;
964         }
965
966         /*
967          * Set the address of the CA message and
968          * return the length of processed data
969          */
970         *hpp = hp;
971         return(proc_len);
972
973 hello_invalid:
974         if (hp)
975                 scsp_free_hello(hp);
976         return(0);
977 }
978
979
980 /*
981  * Parse an SCSP input packet
982  *
983  * Arguments:
984  *      buff    pointer to input packet
985  *      pdu_len length of input packet
986  *
987  * Returns:
988  *      NULL    input packet was invalid
989  *      else    pointer to packet in internal format
990  *
991  */
992 Scsp_msg *
993 scsp_parse_msg(buff, pdu_len)
994         char                    *buff;
995         int                     pdu_len;
996 {
997         int                     ext_off, len, plen;
998         struct scsp_nhdr        *shp;
999         Scsp_msg                *msg = (Scsp_msg *)0;
1000         Scsp_ext                **expp;
1001
1002         /*
1003          * Check the message checksum
1004          */
1005         if (ip_checksum(buff, pdu_len) != 0) {
1006                 /*
1007                  * Checksum was bad--discard the message
1008                  */
1009                 goto ignore;
1010         }
1011
1012         /*
1013          * Allocate storage for the message
1014          */
1015         msg = (Scsp_msg *)UM_ALLOC(sizeof(Scsp_msg));
1016         if (!msg) {
1017                 goto ignore;
1018         }
1019         UM_ZERO(msg, sizeof(Scsp_msg));
1020
1021         /*
1022          * Decode the fixed header
1023          *
1024          * Check the version
1025          */
1026         shp = (struct scsp_nhdr *)buff;
1027         if (shp->sh_ver != SCSP_VER_1)
1028                 goto ignore;
1029
1030         /*
1031          * Get the message type
1032          */
1033         msg->sc_msg_type = shp->sh_type;
1034
1035         /*
1036          * Get and check the length
1037          */
1038         len = ntohs(shp->sh_len);
1039         if (len != pdu_len)
1040                 goto ignore;
1041
1042         /*
1043          * Get the extension offset
1044          */
1045         ext_off = ntohs(shp->sh_ext_off);
1046
1047         /*
1048          * Decode the body of the message, depending on the type
1049          */
1050         buff += sizeof(struct scsp_nhdr);
1051         len -= sizeof(struct scsp_nhdr);
1052         switch(msg->sc_msg_type) {
1053         case SCSP_CA_MSG:
1054                 plen = scsp_parse_ca(buff, len, &msg->sc_ca);
1055                 break;
1056         case SCSP_CSU_REQ_MSG:
1057         case SCSP_CSU_REPLY_MSG:
1058         case SCSP_CSUS_MSG:
1059                 plen = scsp_parse_csu(buff, len, &msg->sc_csu_msg);
1060                 break;
1061         case SCSP_HELLO_MSG:
1062                 plen = scsp_parse_hello(buff, len, &msg->sc_hello);
1063                 break;
1064         default:
1065                 goto ignore;
1066         }
1067         if (plen == 0) {
1068                 goto ignore;
1069         }
1070         buff += plen;
1071         len -= plen;
1072
1073         /*
1074          * Decode any extensions
1075          */
1076         if (ext_off != 0) {
1077                 for (expp = &msg->sc_ext; len > 0;
1078                                 expp = &(*expp)->next) {
1079                         plen = scsp_parse_ext(buff, len, expp);
1080                         if (plen == 0) {
1081                                 goto ignore;
1082                         }
1083                         buff += plen;
1084                         len -= plen;
1085                 }
1086         }
1087
1088         /*
1089          * Make sure we handled the whole message
1090          */
1091         if (len != 0) {
1092                 goto ignore;
1093         }
1094
1095         /*
1096          * Return the address of the SCSP message in internal format
1097          */
1098         return(msg);
1099
1100 ignore:
1101         if (msg)
1102                 scsp_free_msg(msg);
1103         return(Scsp_msg *)0;
1104 }