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