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