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