3 * ===================================
4 * HARP | Host ATM Research Platform
5 * ===================================
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.
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.
21 * Copyright 1994-1998 Network Computing Services, Inc.
23 * Copies of this Software may be made, however, the above copyright
24 * notice must be reproduced on all copies.
26 * @(#) $FreeBSD: src/sys/netatm/uni/unisig_msg.c,v 1.6 2000/01/17 20:49:56 mks Exp $
30 * ATM Forum UNI 3.0/3.1 Signalling Manager
31 * ----------------------------------------
33 * Message handling module
37 #include <netproto/atm/kern_include.h>
39 #include "unisig_var.h"
40 #include "unisig_msg.h"
41 #include "unisig_mbuf.h"
42 #include "unisig_print.h"
47 static void unisig_rcv_restart (struct unisig *, struct unisig_msg *);
48 static void unisig_rcv_setup (struct unisig *, struct unisig_msg *);
55 static int unisig_print_msg = 0;
60 * Set a Cause IE based on information in an ATM attribute block
63 * iep pointer to a cause IE
64 * aap pointer to attribute block
68 * errno error encountered
72 unisig_cause_from_attr(struct ie_generic *iep, Atm_attributes *aap)
75 * Copy cause info from attribute block to IE
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;
85 * Set a Cause IE based on information in a UNI signalling message
88 * iep pointer to a cause IE
89 * msg pointer to message
90 * cause cause code for the error
94 * errno error encountered
98 unisig_cause_from_msg(struct ie_generic *iep, struct unisig_msg *msg,
101 struct ie_generic *ie1;
105 * Fill out the cause IE fixed fields
107 iep->ie_ident = UNI_IE_CAUS;
108 iep->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
109 iep->ie_caus_cause = cause;
112 * Set diagnostics if indicated
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] =
123 iep->ie_caus_diag_len++;
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;
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] =
143 iep->ie_caus_diag_len++;
152 * Send a UNISIG signalling message
154 * Called to send a Q.2931 message. This routine encodes the message
155 * and hands it to SSCF for transmission.
158 * usp pointer to UNISIG protocol instance block
159 * msg pointer to message
163 * errno error encountered
167 unisig_send_msg(struct unisig *usp, struct unisig_msg *msg)
172 ATM_DEBUG2("unisig_send_msg: msg=%p, type=%d\n", msg,
176 * Make sure the network is up
178 if (usp->us_state != UNISIG_ACTIVE)
183 * Print the message we're sending.
185 if (unisig_print_msg)
186 usp_print_msg(msg, UNISIG_MSG_OUT);
190 * Convert message to network order
192 err = usf_init(&usf, usp, NULL, USF_ENCODE,
197 err = usf_enc_msg(&usf, msg);
199 ATM_DEBUG1("unisig_send_msg: encode failed with %d\n",
201 KB_FREEALL(usf.usf_m_base);
207 * Print the converted message
209 if (unisig_print_msg > 1)
210 unisig_print_mbuf(usf.usf_m_base);
216 err = atm_cm_saal_data(usp->us_conn, usf.usf_m_base);
218 KB_FREEALL(usf.usf_m_base);
225 * Send a SETUP request
227 * Build and send a Q.2931 SETUP message.
230 * usp pointer to UNISIG protocol instance block
231 * uvp pointer to VCCB for which the request is being sent
238 unisig_send_setup(struct unisig *usp, struct unisig_vccb *uvp)
241 struct unisig_msg *setup;
242 Atm_attributes *ap = &uvp->uv_connvc->cvc_attr;
244 ATM_DEBUG1("unisig_send_setup: uvp=%p\n", uvp);
247 * Make sure required connection attriutes are set
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) {
260 * Get memory for a SETUP message
262 setup = (struct unisig_msg *)atm_allocate(&unisig_msgpool);
269 * Fill in the SETUP message
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;
277 * Set IEs from connection attributes
279 err = unisig_set_attrs(usp, setup, ap);
284 * Attach a Calling Party Number IE if the user didn't
285 * specify one in the attribute block
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) {
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);
303 * Send the SETUP message
305 err = unisig_send_msg(usp, setup);
309 unisig_free_msg(setup);
316 * Send a RELEASE message
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
332 unisig_send_release(struct unisig *usp, struct unisig_vccb *uvp,
333 struct unisig_msg *msg, int cause)
336 struct unisig_msg *rls_msg;
337 struct ie_generic *cause_ie;
339 ATM_DEBUG2("unisig_send_release: usp=%p, uvp=%p\n",
343 * Get memory for a RELEASE message
345 rls_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
346 if (rls_msg == NULL) {
349 cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
350 if (cause_ie == NULL) {
356 * Fill in the RELEASE message
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;
365 * Fill out the cause IE
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);
372 cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
373 unisig_cause_from_msg(cause_ie, msg, cause);
379 err = unisig_send_msg(usp, rls_msg);
380 unisig_free_msg(rls_msg);
387 * Send a RELEASE COMPLETE message
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
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
401 * errno error encountered
405 unisig_send_release_complete(struct unisig *usp, struct unisig_vccb *uvp,
406 struct unisig_msg *msg, int cause)
409 struct unisig_msg *rls_cmp;
410 struct ie_generic *cause_ie;
412 ATM_DEBUG4("unisig_send_release_complete usp=%p, uvp=%p, msg=%p, cause=%d\n",
413 usp, uvp, msg, cause);
416 * Get memory for a RELEASE COMPLETE message
418 rls_cmp = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
419 if (rls_cmp == NULL) {
422 cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
423 if (cause_ie == NULL) {
429 * Fill in the RELEASE COMPLETE message
432 rls_cmp->msg_call_ref = uvp->uv_call_ref;
434 rls_cmp->msg_call_ref = EXTRACT_CREF(msg->msg_call_ref);
436 rls_cmp->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL;
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;
444 * Fill out the cause IE
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);
451 cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
452 unisig_cause_from_msg(cause_ie, msg, cause);
456 * Send the RELEASE COMPLETE
458 err = unisig_send_msg(usp, rls_cmp);
459 unisig_free_msg(rls_cmp);
466 * Send a STATUS message
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
473 * msg pointer to the message which triggered the send
474 * cause the cause code to include in the message
481 unisig_send_status(struct unisig *usp, struct unisig_vccb *uvp,
482 struct unisig_msg *msg, int cause)
485 struct unisig_msg *stat_msg;
486 struct ie_generic *cause_ie, *clst_ie, *iep;
488 ATM_DEBUG4("unisig_send_status: usp=%p, uvp=%p, msg=%p, cause=%d\n",
489 usp, uvp, msg, cause);
492 * Get memory for a STATUS message
494 stat_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
495 if (stat_msg == NULL) {
498 cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
499 if (cause_ie == NULL) {
503 clst_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
504 if (clst_ie == NULL) {
511 * Fill in the STATUS message
514 stat_msg->msg_call_ref = uvp->uv_call_ref;
516 stat_msg->msg_call_ref =
517 EXTRACT_CREF(msg->msg_call_ref);
519 stat_msg->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL;
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;
528 * Fill out the call state IE
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;
535 clst_ie->ie_clst_state = uvp->uv_sstate;
537 clst_ie->ie_clst_state = UNI_NULL;
541 * Fill out the cause IE
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;
550 case UNI_IE_CAUS_MTEXIST:
551 case UNI_IE_CAUS_STATE:
553 cause_ie->ie_caus_diagnostic[0] = msg->msg_type;
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] =
570 * Send the STATUS message
572 err = unisig_send_msg(usp, stat_msg);
573 unisig_free_msg(stat_msg);
580 * Process a RESTART message
583 * usp pointer to UNISIG protocol instance block
584 * msg pointer to the RESTART message
591 unisig_rcv_restart(struct unisig *usp, struct unisig_msg *msg)
593 struct unisig_vccb *uvp, *uvnext;
594 struct unisig_msg *rsta_msg;
596 ATM_DEBUG2("unisig_rcv_restart: usp=%p, msg=%p\n",
600 * Check what class of VCCs we're supposed to restart
602 if (msg->msg_ie_rsti->ie_rsti_class == UNI_IE_RSTI_IND_VC) {
604 * Just restart the indicated VCC
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,
611 if (uvp && uvp->uv_type & VCC_SVC) {
612 unisig_clear_vcc(usp, uvp,
613 T_ATM_CAUSE_NORMAL_CALL_CLEARING);
621 for (uvp=Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp;
623 uvnext = Q_NEXT(uvp, struct unisig_vccb,
625 if (uvp->uv_type & VCC_SVC) {
626 unisig_clear_vcc(usp, uvp,
627 T_ATM_CAUSE_NORMAL_CALL_CLEARING);
634 * Get memory for a RESTART ACKNOWLEDGE message
636 rsta_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
637 if (rsta_msg == NULL) {
642 * Fill out the message
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;
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);
666 * Process a SETUP message
669 * usp pointer to UNISIG protocol instance block
670 * msg pointer to the SETUP message
677 unisig_rcv_setup(struct unisig *usp, struct unisig_msg *msg)
679 struct unisig_vccb *uvp = NULL;
680 struct ie_generic *iep;
682 ATM_DEBUG2("unisig_rcv_setup: usp=%p, msg=%p\n", usp, msg);
685 * If we already have a VCC with the call reference,
686 * ignore the SETUP message
688 uvp = unisig_find_conn(usp, EXTRACT_CREF(msg->msg_call_ref));
693 * If the call reference flag is incorrectly set,
694 * ignore the SETUP message
696 if (msg->msg_call_ref & UNI_MSG_CALL_REF_RMT)
700 * If there are missing mandatory IEs, send a
701 * RELEASE COMPLETE message and ignore the SETUP
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);
712 * If there are mandatory IEs with invalid content, send a
713 * RELEASE COMPLETE message and ignore the SETUP
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,
719 UNI_IE_CAUS_IECONTENT);
725 * Get a new VCCB for the connection
727 uvp = (struct unisig_vccb *)atm_allocate(&unisig_vcpool);
733 * Put the VCCB on the UNISIG queue
735 ENQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq);
738 * Set the state and call reference value
740 uvp->uv_sstate = UNI_NULL;
741 uvp->uv_call_ref = EXTRACT_CREF(msg->msg_call_ref);
744 * Pass the VCCB and message to the VC state machine
746 unisig_vc_state(usp, uvp, UNI_VC_SETUP_MSG, msg);
749 * If the VCCB state is NULL, the open failed and the
750 * VCCB should be released
752 if (uvp->uv_sstate == UNI_NULL) {
753 DEQUEUE(uvp, struct unisig_vccb, uv_sigelem,
763 * Process a UNISIG signalling message
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.
770 * usp pointer to UNISIG protocol instance block
771 * m pointer to a buffer chain containing the UNISIG message
778 unisig_rcv_msg(struct unisig *usp, KBuffer *m)
783 struct unisig_msg *msg = NULL;
784 struct unisig_vccb *uvp = NULL;
785 struct ie_generic *iep;
787 ATM_DEBUG2("unisig_rcv_msg: bfr=%p, len=%d\n", m, KB_LEN(m));
790 unisig_print_mbuf(m);
794 * Get storage for the message
796 msg = (struct unisig_msg *)atm_allocate(&unisig_msgpool);
803 * Convert the message from network order to internal format
805 err = usf_init(&usf, usp, m, USF_DECODE, 0);
808 panic("unisig_rcv_msg: invalid parameter");
809 ATM_DEBUG1("unisig_rcv_msg: decode init failed with %d\n",
814 err = usf_dec_msg(&usf, msg);
816 ATM_DEBUG1("unisig_rcv_msg: decode failed with %d\n",
823 * Debug--print some information about the message
825 if (unisig_print_msg)
826 usp_print_msg(msg, UNISIG_MSG_IN);
830 * Get the call reference value
832 cref = EXTRACT_CREF(msg->msg_call_ref);
835 * Any message with the global call reference value except
836 * RESTART, RESTART ACK, or STATUS is in error
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) {
843 * Send STATUS message indicating the error
845 err = unisig_send_status(usp, NULL,
846 msg, UNI_IE_CAUS_CREF);
851 * Check for missing mandatory IEs. Checks for SETUP,
852 * RELEASE, and RELEASE COMPLETE are handled elsewhere.
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,
861 UNI_IE_CAUS_MISSING);
868 * Find the VCCB associated with the message
870 uvp = unisig_find_conn(usp, cref);
873 * Process the message based on its type
875 switch(msg->msg_type) {
877 unisig_vc_state(usp, uvp,
878 UNI_VC_CALLP_MSG, msg);
881 unisig_vc_state(usp, uvp,
882 UNI_VC_CONNECT_MSG, msg);
885 unisig_vc_state(usp, uvp,
886 UNI_VC_CNCTACK_MSG, msg);
889 unisig_rcv_setup(usp, msg);
892 unisig_vc_state(usp, uvp,
893 UNI_VC_RELEASE_MSG, msg);
897 * Ignore a RELEASE COMPLETE with an unrecognized
898 * call reference value
901 unisig_vc_state(usp, uvp,
902 UNI_VC_RLSCMP_MSG, msg);
906 unisig_rcv_restart(usp, msg);
911 unisig_vc_state(usp, uvp,
912 UNI_VC_STATUS_MSG, msg);
915 unisig_vc_state(usp, uvp,
916 UNI_VC_STATUSENQ_MSG, msg);
919 unisig_vc_state(usp, uvp,
920 UNI_VC_ADDP_MSG, msg);
923 unisig_vc_state(usp, uvp,
924 UNI_VC_ADDPACK_MSG, msg);
927 unisig_vc_state(usp, uvp,
928 UNI_VC_ADDPREJ_MSG, msg);
931 unisig_vc_state(usp, uvp,
932 UNI_VC_DROP_MSG, msg);
935 unisig_vc_state(usp, uvp,
936 UNI_VC_DROPACK_MSG, msg);
940 * Message size didn't match size received
942 err = unisig_send_status(usp, uvp, msg,
943 UNI_IE_CAUS_MTEXIST);
948 * Handle message errors that require a response
953 * Message size didn't match size received
955 err = unisig_send_status(usp, uvp, msg,
961 * Free the incoming message (both buffer and internal format)
965 unisig_free_msg(msg);