Add the DragonFly cvs id and perform general cleanups on cvs/rcs/sccs ids. Most
[dragonfly.git] / sys / netproto / atm / uni / unisig_msg.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/sys/netatm/uni/unisig_msg.c,v 1.6 2000/01/17 20:49:56 mks Exp $
27  *      @(#) $DragonFly: src/sys/netproto/atm/uni/unisig_msg.c,v 1.2 2003/06/17 04:28:49 dillon Exp $
28  */
29
30 /*
31  * ATM Forum UNI 3.0/3.1 Signalling Manager
32  * ----------------------------------------
33  *
34  * Message handling module
35  *
36  */
37
38 #include <netatm/kern_include.h>
39
40 #include <netatm/uni/unisig_var.h>
41 #include <netatm/uni/unisig_msg.h>
42 #include <netatm/uni/unisig_mbuf.h>
43 #include <netatm/uni/unisig_print.h>
44
45 /*
46  * Local functions
47  */
48 static void     unisig_rcv_restart __P((struct unisig *, struct unisig_msg *));
49 static void     unisig_rcv_setup __P((struct unisig *, struct unisig_msg *));
50
51
52 /*
53  * Local variables
54  */
55 #ifdef DIAGNOSTIC
56 static int      unisig_print_msg = 0;
57 #endif
58
59
60 /*
61  * Set a Cause IE based on information in an ATM attribute block
62  *
63  * Arguments:
64  *      iep     pointer to a cause IE
65  *      aap     pointer to attribute block
66  *
67  * Returns:
68  *      0       message sent OK
69  *      errno   error encountered
70  *
71  */
72 void
73 unisig_cause_from_attr(iep, aap)
74         struct ie_generic       *iep;
75         Atm_attributes          *aap;
76 {
77         /*
78          * Copy cause info from attribute block to IE
79          */
80         iep->ie_ident = UNI_IE_CAUS;
81         iep->ie_coding = aap->cause.v.coding_standard;
82         iep->ie_caus_loc = aap->cause.v.location;
83         iep->ie_caus_cause = aap->cause.v.cause_value;
84 }
85
86
87 /*
88  * Set a Cause IE based on information in a UNI signalling message
89  *
90  * Arguments:
91  *      iep     pointer to a cause IE
92  *      msg     pointer to message
93  *      cause   cause code for the error
94  *
95  * Returns:
96  *      0       message sent OK
97  *      errno   error encountered
98  *
99  */
100 void
101 unisig_cause_from_msg(iep, msg, cause)
102         struct ie_generic       *iep;
103         struct unisig_msg       *msg;
104         int                     cause;
105 {
106         struct ie_generic       *ie1;
107         int                     i;
108
109         /*
110          * Fill out the cause IE fixed fields
111          */
112         iep->ie_ident = UNI_IE_CAUS;
113         iep->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
114         iep->ie_caus_cause = cause;
115
116         /*
117          * Set diagnostics if indicated
118          */
119         switch(cause) {
120         case UNI_IE_CAUS_IECONTENT:
121                 iep->ie_caus_diag_len = 0;
122                 for (i = 0, ie1 = msg->msg_ie_err;
123                                 ie1 && i < UNI_IE_CAUS_MAX_ID;
124                                 ie1 = ie1->ie_next) {
125                         if (ie1->ie_err_cause == UNI_IE_CAUS_IECONTENT) {
126                                 iep->ie_caus_diagnostic[i] =
127                                                 ie1->ie_ident;
128                                 iep->ie_caus_diag_len++;
129                                 i++;
130                         }
131                 }
132                 break;
133         case UNI_IE_CAUS_REJECT:
134                 iep->ie_caus_diag_len = 2;
135                 iep->ie_caus_diagnostic[0] = UNI_IE_EXT_BIT +
136                                 (UNI_IE_CAUS_RR_USER << UNI_IE_CAUS_RR_SHIFT) +
137                                 UNI_IE_CAUS_RC_TRANS;
138                 iep->ie_caus_diagnostic[1] = 0;
139                 break;
140         case UNI_IE_CAUS_MISSING:
141                 iep->ie_caus_diag_len = 0;
142                 for (i = 0, ie1 = msg->msg_ie_err;
143                                 ie1 && i < UNI_IE_CAUS_MAX_ID;
144                                 ie1 = ie1->ie_next) {
145                         if (ie1->ie_err_cause == UNI_IE_CAUS_MISSING) {
146                                 iep->ie_caus_diagnostic[i] =
147                                                 ie1->ie_ident;
148                                 iep->ie_caus_diag_len++;
149                                 i++;
150                         }
151                 }
152         }
153 }
154
155
156 /*
157  * Send a UNISIG signalling message
158  *
159  * Called to send a Q.2931 message.  This routine encodes the message
160  * and hands it to SSCF for transmission.
161  *
162  * Arguments:
163  *      usp     pointer to UNISIG protocol instance block
164  *      msg     pointer to message
165  *
166  * Returns:
167  *      0       message sent OK
168  *      errno   error encountered
169  *
170  */
171 int
172 unisig_send_msg(usp, msg)
173         struct unisig           *usp;
174         struct unisig_msg       *msg;
175 {
176         int             err = 0;
177         struct usfmt    usf;
178
179         ATM_DEBUG2("unisig_send_msg: msg=%p, type=%d\n", msg,
180                         msg->msg_type);
181
182         /*
183          * Make sure the network is up
184          */
185         if (usp->us_state != UNISIG_ACTIVE)
186                 return(ENETDOWN);
187
188 #ifdef DIAGNOSTIC
189         /*
190          * Print the message we're sending.
191          */
192         if (unisig_print_msg)
193                 usp_print_msg(msg, UNISIG_MSG_OUT);
194 #endif
195
196         /*
197          * Convert message to network order
198          */
199         err = usf_init(&usf, usp, (KBuffer *) 0, USF_ENCODE,
200                         usp->us_headout);
201         if (err)
202                 return(err);
203
204         err = usf_enc_msg(&usf, msg);
205         if (err) {
206                 ATM_DEBUG1("unisig_send_msg: encode failed with %d\n",
207                                 err);
208                 KB_FREEALL(usf.usf_m_base);
209                 return(EIO);
210         }
211
212 #ifdef DIAGNOSTIC
213         /*
214          * Print the converted message
215          */
216         if (unisig_print_msg > 1)
217                 unisig_print_mbuf(usf.usf_m_base);
218 #endif
219
220         /*
221          * Send the message
222          */
223         err = atm_cm_saal_data(usp->us_conn, usf.usf_m_base);
224         if (err)
225                 KB_FREEALL(usf.usf_m_base);
226
227         return(err);
228 }
229
230
231 /*
232  * Send a SETUP request
233  *
234  * Build and send a Q.2931 SETUP message.
235  *
236  * Arguments:
237  *      usp     pointer to UNISIG protocol instance block
238  *      uvp     pointer to VCCB for which the request is being sent
239  *
240  * Returns:
241  *      none
242  *
243  */
244 int
245 unisig_send_setup(usp, uvp)
246         struct  unisig          *usp;
247         struct  unisig_vccb     *uvp;
248 {
249         int                     err = 0;
250         struct unisig_msg       *setup;
251         Atm_attributes          *ap = &uvp->uv_connvc->cvc_attr;
252
253         ATM_DEBUG1("unisig_send_setup: uvp=%p\n", uvp);
254
255         /*
256          * Make sure required connection attriutes are set
257          */
258         if (ap->aal.tag != T_ATM_PRESENT ||
259                         ap->traffic.tag != T_ATM_PRESENT ||
260                         ap->bearer.tag != T_ATM_PRESENT ||
261                         ap->called.tag != T_ATM_PRESENT ||
262                         ap->qos.tag != T_ATM_PRESENT) {
263                 err = EINVAL;
264                 setup = NULL;
265                 goto done;
266         }
267
268         /*
269          * Get memory for a SETUP message
270          */
271         setup = (struct unisig_msg *)atm_allocate(&unisig_msgpool);
272         if (setup == NULL) {
273                 err = ENOMEM;
274                 goto done;
275         }
276
277         /*
278          * Fill in the SETUP message
279          */
280         if (!uvp->uv_call_ref)
281                 uvp->uv_call_ref = unisig_alloc_call_ref(usp);
282         setup->msg_call_ref = uvp->uv_call_ref;
283         setup->msg_type = UNI_MSG_SETU;
284
285         /*
286          * Set IEs from connection attributes
287          */
288         err = unisig_set_attrs(usp, setup, ap);
289         if (err)
290                 goto done;
291
292         /*
293          * Attach a Calling Party Number IE if the user didn't
294          * specify one in the attribute block
295          */
296         if (ap->calling.tag != T_ATM_PRESENT) {
297                 setup->msg_ie_cgad = (struct ie_generic *)
298                                 atm_allocate(&unisig_iepool);
299                 if (setup->msg_ie_cgad == NULL) {
300                         err = ENOMEM;
301                         goto done;
302                 }
303                 setup->msg_ie_cgad->ie_ident = UNI_IE_CGAD;
304                 ATM_ADDR_COPY(&usp->us_addr,
305                                 &setup->msg_ie_cgad->ie_cgad_addr);
306                 ATM_ADDR_SEL_COPY(&usp->us_addr, 
307                                 uvp->uv_nif ? uvp->uv_nif->nif_sel : 0, 
308                                 &setup->msg_ie_cgad->ie_cgad_addr);
309         }
310
311         /*
312          * Send the SETUP message
313          */
314         err = unisig_send_msg(usp, setup);
315
316 done:
317         if (setup)
318                 unisig_free_msg(setup);
319
320         return(err);
321 }
322
323
324 /*
325  * Send a RELEASE message
326  *
327  * Arguments:
328  *      usp     pointer to UNISIG protocol instance block
329  *      uvp     pointer to VCCB for which the RELEASE is being sent
330  *      msg     pointer to UNI signalling message that the RELEASE
331  *              responds to (may be NULL)
332  *      cause   the reason for the RELEASE; a value of
333  *              T_ATM_ABSENT indicates that the cause code is
334  *              in the VCC's ATM attributes block
335  *
336  * Returns:
337  *      none
338  *
339  */
340 int
341 unisig_send_release(usp, uvp, msg, cause)
342         struct unisig           *usp;
343         struct unisig_vccb      *uvp;
344         struct unisig_msg       *msg;
345         int                     cause;
346 {
347         int                     err = 0;
348         struct unisig_msg       *rls_msg;
349         struct ie_generic       *cause_ie;
350
351         ATM_DEBUG2("unisig_send_release: usp=%p, uvp=%p\n",
352                         usp, uvp);
353
354         /*
355          * Get memory for a RELEASE message
356          */
357         rls_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
358         if (rls_msg == NULL) {
359                 return(ENOMEM);
360         }
361         cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
362         if (cause_ie == NULL) {
363                 atm_free(rls_msg);
364                 return(ENOMEM);
365         }
366
367         /*
368          * Fill in the RELEASE message
369          */
370         rls_msg->msg_call_ref = uvp->uv_call_ref;
371         rls_msg->msg_type = UNI_MSG_RLSE;
372         rls_msg->msg_type_flag = 0;
373         rls_msg->msg_type_action = 0;
374         rls_msg->msg_ie_caus = cause_ie;
375
376         /*
377          * Fill out the cause IE
378          */
379         cause_ie->ie_ident = UNI_IE_CAUS;
380         if (cause == T_ATM_ABSENT) {
381                 unisig_cause_from_attr(cause_ie,
382                                 &uvp->uv_connvc->cvc_attr);
383         } else {
384                 cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
385                 unisig_cause_from_msg(cause_ie, msg, cause);
386         }
387
388         /*
389          * Send the RELEASE
390          */
391         err = unisig_send_msg(usp, rls_msg);
392         unisig_free_msg(rls_msg);
393
394         return(err);
395 }
396
397
398 /*
399  * Send a RELEASE COMPLETE message
400  *
401  * Arguments:
402  *      usp     pointer to UNISIG protocol instance block
403  *      uvp     pointer to VCCB for which the RELEASE is being sent.
404  *              NULL indicates that a VCCB wasn't found for a call
405  *              reference value.
406  *      msg     pointer to the message which triggered the send
407  *      cause   the cause code for the message; a value of
408  *              T_ATM_ABSENT indicates that the cause code is
409  *              in the VCC's ATM attributes block
410  *
411  * Returns:
412  *      0       success
413  *      errno   error encountered
414  *
415  */
416 int
417 unisig_send_release_complete(usp, uvp, msg, cause)
418         struct unisig           *usp;
419         struct unisig_vccb      *uvp;
420         struct unisig_msg       *msg;
421         int                     cause;
422 {
423         int                     err = 0;
424         struct unisig_msg       *rls_cmp;
425         struct ie_generic       *cause_ie;
426
427         ATM_DEBUG4("unisig_send_release_complete usp=%p, uvp=%p, msg=%p, cause=%d\n",
428                         usp, uvp, msg, cause);
429
430         /*
431          * Get memory for a RELEASE COMPLETE message
432          */
433         rls_cmp = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
434         if (rls_cmp == NULL) {
435                 return(ENOMEM);
436         }
437         cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
438         if (cause_ie == NULL) {
439                 atm_free(rls_cmp);
440                 return(ENOMEM);
441         }
442
443         /*
444          * Fill in the RELEASE COMPLETE message
445          */
446         if (uvp) {
447                 rls_cmp->msg_call_ref = uvp->uv_call_ref;
448         } else if (msg) {
449                 rls_cmp->msg_call_ref = EXTRACT_CREF(msg->msg_call_ref);
450         } else {
451                 rls_cmp->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL;
452         }
453         rls_cmp->msg_type = UNI_MSG_RLSC;
454         rls_cmp->msg_type_flag = 0;
455         rls_cmp->msg_type_action = 0;
456         rls_cmp->msg_ie_caus = cause_ie;
457
458         /*
459          * Fill out the cause IE
460          */
461         cause_ie->ie_ident = UNI_IE_CAUS;
462         if (cause == T_ATM_ABSENT) {
463                 unisig_cause_from_attr(cause_ie,
464                                 &uvp->uv_connvc->cvc_attr);
465         } else {
466                 cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
467                 unisig_cause_from_msg(cause_ie, msg, cause);
468         }
469
470         /*
471          * Send the RELEASE COMPLETE
472          */
473         err = unisig_send_msg(usp, rls_cmp);
474         unisig_free_msg(rls_cmp);
475
476         return(err);
477 }
478
479
480 /*
481  * Send a STATUS message
482  *
483  * Arguments:
484  *      usp     pointer to UNISIG protocol instance block
485  *      uvp     pointer to VCCB for which the STATUS is being sent.
486  *              NULL indicates that a VCCB wasn't found for a call
487  *              reference value.
488  *      msg     pointer to the message which triggered the send
489  *      cause   the cause code to include in the message
490  *
491  * Returns:
492  *      none
493  *
494  */
495 int
496 unisig_send_status(usp, uvp, msg, cause)
497         struct unisig           *usp;
498         struct  unisig_vccb     *uvp;
499         struct unisig_msg       *msg;
500         int                     cause;
501 {
502         int                     err = 0, i;
503         struct unisig_msg       *stat_msg;
504         struct ie_generic       *cause_ie, *clst_ie, *iep;
505
506         ATM_DEBUG4("unisig_send_status: usp=%p, uvp=%p, msg=%p, cause=%d\n",
507                         usp, uvp, msg, cause);
508
509         /*
510          * Get memory for a STATUS message
511          */
512         stat_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
513         if (stat_msg == NULL) {
514                 return(ENOMEM);
515         }
516         cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
517         if (cause_ie == NULL) {
518                 atm_free(stat_msg);
519                 return(ENOMEM);
520         }
521         clst_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
522         if (clst_ie == NULL) {
523                 atm_free(stat_msg);
524                 atm_free(cause_ie);
525                 return(ENOMEM);
526         }
527
528         /*
529          * Fill in the STATUS message
530          */
531         if (uvp) {
532                 stat_msg->msg_call_ref = uvp->uv_call_ref;
533         } else if (msg) {
534                 stat_msg->msg_call_ref =
535                                 EXTRACT_CREF(msg->msg_call_ref);
536         } else {
537                 stat_msg->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL;
538         }
539         stat_msg->msg_type = UNI_MSG_STAT;
540         stat_msg->msg_type_flag = 0;
541         stat_msg->msg_type_action = 0;
542         stat_msg->msg_ie_clst = clst_ie;
543         stat_msg->msg_ie_caus = cause_ie;
544
545         /*
546          * Fill out the call state IE
547          */
548         clst_ie->ie_ident = UNI_IE_CLST;
549         clst_ie->ie_coding = 0;
550         clst_ie->ie_flag = 0;
551         clst_ie->ie_action = 0;
552         if (uvp) {
553                 clst_ie->ie_clst_state = uvp->uv_sstate;
554         } else {
555                 clst_ie->ie_clst_state = UNI_NULL;
556         }
557
558         /*
559          * Fill out the cause IE
560          */
561         cause_ie->ie_ident = UNI_IE_CAUS;
562         cause_ie->ie_coding = 0;
563         cause_ie->ie_flag = 0;
564         cause_ie->ie_action = 0;
565         cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
566         cause_ie->ie_caus_cause = cause;
567         switch (cause) {
568         case UNI_IE_CAUS_MTEXIST:
569         case UNI_IE_CAUS_STATE:
570                 if (msg) {
571                         cause_ie->ie_caus_diagnostic[0] = msg->msg_type;
572                 }
573                 break;
574         case UNI_IE_CAUS_MISSING:
575         case UNI_IE_CAUS_IECONTENT:
576         case UNI_IE_CAUS_IEEXIST:
577                 for (i=0, iep=msg->msg_ie_err;
578                                 iep && i<UNI_MSG_IE_CNT;
579                                 i++, iep = iep->ie_next) {
580                         if (iep->ie_err_cause == cause) {
581                                 cause_ie->ie_caus_diagnostic[i] =
582                                                 iep->ie_ident;
583                         }
584                 }
585         }
586
587         /*
588          * Send the STATUS message
589          */
590         err = unisig_send_msg(usp, stat_msg);
591         unisig_free_msg(stat_msg);
592
593         return(err);
594 }
595
596
597 /*
598  * Process a RESTART message
599  *
600  * Arguments:
601  *      usp     pointer to UNISIG protocol instance block
602  *      msg     pointer to the RESTART message
603  *
604  * Returns:
605  *      none
606  *
607  */
608 static void
609 unisig_rcv_restart(usp, msg)
610         struct unisig           *usp;
611         struct unisig_msg       *msg;
612 {
613         struct unisig_vccb      *uvp, *uvnext;
614         struct unisig_msg       *rsta_msg;
615         int                     s;
616
617         ATM_DEBUG2("unisig_rcv_restart: usp=%p, msg=%p\n",
618                         usp, msg);
619
620         /*
621          * Check what class of VCCs we're supposed to restart
622          */
623         if (msg->msg_ie_rsti->ie_rsti_class == UNI_IE_RSTI_IND_VC) {
624                 /*
625                  * Just restart the indicated VCC
626                  */
627                 if (msg->msg_ie_cnid) {
628                         uvp = unisig_find_vpvc(usp,
629                                         msg->msg_ie_cnid->ie_cnid_vpci,
630                                         msg->msg_ie_cnid->ie_cnid_vci,
631                                         0);
632                         if (uvp && uvp->uv_type & VCC_SVC) {
633                                 (void) unisig_clear_vcc(usp, uvp,
634                                                 T_ATM_CAUSE_NORMAL_CALL_CLEARING);
635                         }
636                 }
637         } else {
638                 /*
639                  * Restart all VCCs
640                  */
641                 s = splnet();
642                 for (uvp=Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp;
643                                 uvp=uvnext) {
644                         uvnext = Q_NEXT(uvp, struct unisig_vccb,
645                                         uv_sigelem);
646                         if (uvp->uv_type & VCC_SVC) {
647                                 (void) unisig_clear_vcc(usp, uvp,
648                                                 T_ATM_CAUSE_NORMAL_CALL_CLEARING);
649                         }
650                 }
651                 (void) splx(s);
652         }
653
654         /*
655          * Get memory for a RESTART ACKNOWLEDGE message
656          */
657         rsta_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
658         if (rsta_msg == NULL) {
659                 return;
660         }
661
662         /*
663          * Fill out the message
664          */
665         rsta_msg->msg_call_ref = EXTRACT_CREF(msg->msg_call_ref);
666         rsta_msg->msg_type = UNI_MSG_RSTA;
667         rsta_msg->msg_type_flag = 0;
668         rsta_msg->msg_type_action = 0;
669         rsta_msg->msg_ie_rsti = msg->msg_ie_rsti;
670         if (msg->msg_ie_cnid) {
671                 rsta_msg->msg_ie_cnid = msg->msg_ie_cnid;
672         }
673
674         /*
675          * Send the message
676          */
677         (void) unisig_send_msg(usp, rsta_msg);
678         rsta_msg->msg_ie_rsti = NULL;
679         rsta_msg->msg_ie_cnid = NULL;
680         unisig_free_msg(rsta_msg);
681
682         return;
683 }
684
685
686 /*
687  * Process a SETUP message
688  *
689  * Arguments:
690  *      usp     pointer to UNISIG protocol instance block
691  *      msg     pointer to the SETUP message
692  *
693  * Returns:
694  *      none
695  *
696  */
697 static void
698 unisig_rcv_setup(usp, msg)
699         struct unisig           *usp;
700         struct unisig_msg       *msg;
701 {
702         struct unisig_vccb      *uvp = NULL;
703         struct ie_generic       *iep;
704
705         ATM_DEBUG2("unisig_rcv_setup: usp=%p, msg=%p\n", usp, msg);
706
707         /*
708          * If we already have a VCC with the call reference,
709          * ignore the SETUP message
710          */
711         uvp = unisig_find_conn(usp, EXTRACT_CREF(msg->msg_call_ref));
712         if (uvp)
713                 return;
714
715         /*
716          * If the call reference flag is incorrectly set, 
717          * ignore the SETUP message
718          */
719         if (msg->msg_call_ref & UNI_MSG_CALL_REF_RMT)
720                 return;
721
722         /*
723          * If there are missing mandatory IEs, send a
724          * RELEASE COMPLETE message and ignore the SETUP
725          */
726         for (iep = msg->msg_ie_err; iep; iep = iep->ie_next) {
727                 if (iep->ie_err_cause == UNI_IE_CAUS_MISSING) {
728                         (void) unisig_send_release_complete(usp,
729                                         uvp, msg, UNI_IE_CAUS_MISSING);
730                         return;
731                 }
732         }
733
734         /*
735          * If there are mandatory IEs with invalid content, send a
736          * RELEASE COMPLETE message and ignore the SETUP
737          */
738         for (iep = msg->msg_ie_err; iep; iep = iep->ie_next) {
739                 if (iep->ie_err_cause == UNI_IE_CAUS_IECONTENT) {
740                         (void) unisig_send_release_complete(usp,
741                                         uvp, msg,
742                                         UNI_IE_CAUS_IECONTENT);
743                         return;
744                 }
745         }
746
747         /*
748          * Get a new VCCB for the connection
749          */
750         uvp = (struct unisig_vccb *)atm_allocate(&unisig_vcpool);
751         if (uvp == NULL) {
752                 return;
753         }
754
755         /*
756          * Put the VCCB on the UNISIG queue
757          */
758         ENQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq);
759
760         /*
761          * Set the state and call reference value
762          */
763         uvp->uv_sstate = UNI_NULL;
764         uvp->uv_call_ref = EXTRACT_CREF(msg->msg_call_ref);
765
766         /*
767          * Pass the VCCB and message to the VC state machine
768          */
769         (void) unisig_vc_state(usp, uvp, UNI_VC_SETUP_MSG, msg);
770
771         /*
772          * If the VCCB state is NULL, the open failed and the
773          * VCCB should be released
774          */
775         if (uvp->uv_sstate == UNI_NULL) {
776                 DEQUEUE(uvp, struct unisig_vccb, uv_sigelem,
777                                 usp->us_vccq);
778                 atm_free(uvp);
779         }
780
781         return;
782 }
783
784
785 /*
786  * Process a UNISIG signalling message
787  *
788  * Called when a UNISIG message is received.  The message is decoded
789  * and passed to the UNISIG state machine.  Unrecognized and
790  * unexpected messages are logged.
791  *
792  * Arguments:
793  *      usp     pointer to UNISIG protocol instance block
794  *      m       pointer to a buffer chain containing the UNISIG message
795  *
796  * Returns:
797  *      none
798  *
799  */
800 int
801 unisig_rcv_msg(usp, m)
802         struct unisig   *usp;
803         KBuffer         *m;
804 {
805         int                     err;
806         u_int                   cref;
807         struct usfmt            usf;
808         struct unisig_msg       *msg = 0;
809         struct unisig_vccb      *uvp = 0;
810         struct ie_generic       *iep;
811
812         ATM_DEBUG2("unisig_rcv_msg: bfr=%p, len=%d\n", m, KB_LEN(m));
813
814 #ifdef NOTDEF
815         unisig_print_mbuf(m);
816 #endif
817
818         /*
819          * Get storage for the message
820          */
821         msg = (struct unisig_msg *)atm_allocate(&unisig_msgpool);
822         if (msg == NULL) {
823                 err = ENOMEM;
824                 goto done;
825         }
826
827         /*
828          * Convert the message from network order to internal format
829          */
830         err = usf_init(&usf, usp, m, USF_DECODE, 0);
831         if (err) {
832                 if (err == EINVAL)
833                         panic("unisig_rcv_msg: invalid parameter\n");
834                 ATM_DEBUG1("unisig_rcv_msg: decode init failed with %d\n",
835                                 err);
836                 goto done;
837         }
838
839         err = usf_dec_msg(&usf, msg);
840         if (err) {
841                 ATM_DEBUG1("unisig_rcv_msg: decode failed with %d\n",
842                                 err);
843                 goto done;
844         }
845
846 #ifdef DIAGNOSTIC
847         /*
848          * Debug--print some information about the message
849          */
850         if (unisig_print_msg)
851                 usp_print_msg(msg, UNISIG_MSG_IN);
852 #endif
853
854         /*
855          * Get the call reference value
856          */
857         cref = EXTRACT_CREF(msg->msg_call_ref);
858
859         /*
860          * Any message with the global call reference value except
861          * RESTART, RESTART ACK, or STATUS is in error
862          */
863         if (GLOBAL_CREF(cref) &&
864                         msg->msg_type != UNI_MSG_RSTR &&
865                         msg->msg_type != UNI_MSG_RSTA &&
866                         msg->msg_type != UNI_MSG_STAT) {
867                 /*
868                  * Send STATUS message indicating the error
869                  */
870                 err = unisig_send_status(usp, (struct unisig_vccb *) 0,
871                                 msg, UNI_IE_CAUS_CREF);
872                 goto done;
873         }
874
875         /*
876          * Check for missing mandatory IEs.  Checks for SETUP,
877          * RELEASE, and RELEASE COMPLETE are handled elsewhere.
878          */
879         if (msg->msg_type != UNI_MSG_SETU &&
880                         msg->msg_type != UNI_MSG_RLSE &&
881                         msg->msg_type != UNI_MSG_RLSC) {
882                 for (iep = msg->msg_ie_err; iep; iep = iep->ie_next) {
883                         if (iep->ie_err_cause == UNI_IE_CAUS_MISSING) {
884                                 err = unisig_send_status(usp,
885                                                 uvp, msg,
886                                                 UNI_IE_CAUS_MISSING);
887                                 goto done;
888                         }
889                 }
890         }
891
892         /*
893          * Find the VCCB associated with the message
894          */
895         uvp = unisig_find_conn(usp, cref);
896
897         /*
898          * Process the message based on its type
899          */
900         switch(msg->msg_type) {
901         case UNI_MSG_CALP:
902                 (void) unisig_vc_state(usp, uvp,
903                                 UNI_VC_CALLP_MSG, msg);
904                 break;
905         case UNI_MSG_CONN:
906                 (void) unisig_vc_state(usp, uvp,
907                                 UNI_VC_CONNECT_MSG, msg);
908                 break;
909         case UNI_MSG_CACK:
910                 (void) unisig_vc_state(usp, uvp,
911                                 UNI_VC_CNCTACK_MSG, msg);
912                 break;
913         case UNI_MSG_SETU:
914                 unisig_rcv_setup(usp, msg);
915                 break;
916         case UNI_MSG_RLSE:
917                 (void) unisig_vc_state(usp, uvp,
918                                 UNI_VC_RELEASE_MSG, msg);
919                 break;
920         case UNI_MSG_RLSC:
921                 /*
922                  * Ignore a RELEASE COMPLETE with an unrecognized
923                  * call reference value
924                  */
925                 if (uvp) {
926                         (void) unisig_vc_state(usp, uvp,
927                                         UNI_VC_RLSCMP_MSG, msg);
928                 }
929                 break;
930         case UNI_MSG_RSTR:
931                 unisig_rcv_restart(usp, msg);
932                 break;
933         case UNI_MSG_RSTA:
934                 break;
935         case UNI_MSG_STAT:
936                 (void) unisig_vc_state(usp, uvp,
937                                 UNI_VC_STATUS_MSG, msg);
938                 break;
939         case UNI_MSG_SENQ:
940                 (void) unisig_vc_state(usp, uvp,
941                                 UNI_VC_STATUSENQ_MSG, msg);
942                 break;
943         case UNI_MSG_ADDP:
944                 (void) unisig_vc_state(usp, uvp,
945                                 UNI_VC_ADDP_MSG, msg);
946                 break;
947         case UNI_MSG_ADPA:
948                 (void) unisig_vc_state(usp, uvp,
949                                 UNI_VC_ADDPACK_MSG, msg);
950                 break;
951         case UNI_MSG_ADPR:
952                 (void) unisig_vc_state(usp, uvp,
953                                 UNI_VC_ADDPREJ_MSG, msg);
954                 break;
955         case UNI_MSG_DRPP:
956                 (void) unisig_vc_state(usp, uvp,
957                                 UNI_VC_DROP_MSG, msg);
958                 break;
959         case UNI_MSG_DRPA:
960                 (void) unisig_vc_state(usp, uvp,
961                                 UNI_VC_DROPACK_MSG, msg);
962                 break;
963         default:
964                 /*
965                  * Message size didn't match size received
966                  */
967                 err = unisig_send_status(usp, uvp, msg,
968                                 UNI_IE_CAUS_MTEXIST);
969         }
970
971 done:
972         /*
973          * Handle message errors that require a response
974          */
975         switch(err) {
976         case EMSGSIZE:
977                 /*
978                  * Message size didn't match size received
979                  */
980                 err = unisig_send_status(usp, uvp, msg,
981                                 UNI_IE_CAUS_LEN);
982                 break;
983         }
984
985         /*
986          * Free the incoming message (both buffer and internal format)
987          * if necessary.
988          */
989         if (msg)
990                 unisig_free_msg(msg);
991         if (m)
992                 KB_FREEALL(m);
993
994         return (err);
995 }