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