Remove __P macros from src/usr.bin and src/usr.sbin.
[dragonfly.git] / usr.sbin / atm / scspd / scsp_input.c
CommitLineData
984263bc
MD
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 $
2d8a3be7 27 * @(#) $DragonFly: src/usr.sbin/atm/scspd/scsp_input.c,v 1.3 2003/11/03 19:31:35 eirikn Exp $
984263bc
MD
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
2d8a3be7 63static int scsp_parse_atmarp(char *, int, Scsp_atmarp_csa **);
984263bc
MD
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 */
79static u_long
80get_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 */
110static void
111scsp_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 */
147static void
148scsp_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 */
184static void
185scsp_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 */
211void
212scsp_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 */
268static int
269scsp_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 */
313static int
314scsp_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
373mcp_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 */
391static int
392scsp_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
438ext_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 */
460static int
461scsp_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
546csa_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 */
566static int
567scsp_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
629ca_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 */
649static int
650scsp_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
801acs_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 */
823static int
824scsp_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
869csu_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 */
889static int
890scsp_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
968hello_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 */
987Scsp_msg *
988scsp_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
1095ignore:
1096 if (msg)
1097 scsp_free_msg(msg);
1098 return(Scsp_msg *)0;
1099}