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