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