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 $
27 * @(#) $DragonFly: src/sys/netproto/atm/uni/unisig_msg.c,v 1.7 2006/01/14 13:36:39 swildner Exp $
31 * ATM Forum UNI 3.0/3.1 Signalling Manager
32 * ----------------------------------------
34 * Message handling module
38 #include <netproto/atm/kern_include.h>
40 #include "unisig_var.h"
41 #include "unisig_msg.h"
42 #include "unisig_mbuf.h"
43 #include "unisig_print.h"
48 static void unisig_rcv_restart (struct unisig *, struct unisig_msg *);
49 static void unisig_rcv_setup (struct unisig *, struct unisig_msg *);
56 static int unisig_print_msg = 0;
61 * Set a Cause IE based on information in an ATM attribute block
64 * iep pointer to a cause IE
65 * aap pointer to attribute block
69 * errno error encountered
73 unisig_cause_from_attr(struct ie_generic *iep, Atm_attributes *aap)
76 * Copy cause info from attribute block to IE
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;
86 * Set a Cause IE based on information in a UNI signalling message
89 * iep pointer to a cause IE
90 * msg pointer to message
91 * cause cause code for the error
95 * errno error encountered
99 unisig_cause_from_msg(struct ie_generic *iep, struct unisig_msg *msg,
102 struct ie_generic *ie1;
106 * Fill out the cause IE fixed fields
108 iep->ie_ident = UNI_IE_CAUS;
109 iep->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
110 iep->ie_caus_cause = cause;
113 * Set diagnostics if indicated
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] =
124 iep->ie_caus_diag_len++;
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;
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] =
144 iep->ie_caus_diag_len++;
153 * Send a UNISIG signalling message
155 * Called to send a Q.2931 message. This routine encodes the message
156 * and hands it to SSCF for transmission.
159 * usp pointer to UNISIG protocol instance block
160 * msg pointer to message
164 * errno error encountered
168 unisig_send_msg(struct unisig *usp, struct unisig_msg *msg)
173 ATM_DEBUG2("unisig_send_msg: msg=%p, type=%d\n", msg,
177 * Make sure the network is up
179 if (usp->us_state != UNISIG_ACTIVE)
184 * Print the message we're sending.
186 if (unisig_print_msg)
187 usp_print_msg(msg, UNISIG_MSG_OUT);
191 * Convert message to network order
193 err = usf_init(&usf, usp, NULL, USF_ENCODE,
198 err = usf_enc_msg(&usf, msg);
200 ATM_DEBUG1("unisig_send_msg: encode failed with %d\n",
202 KB_FREEALL(usf.usf_m_base);
208 * Print the converted message
210 if (unisig_print_msg > 1)
211 unisig_print_mbuf(usf.usf_m_base);
217 err = atm_cm_saal_data(usp->us_conn, usf.usf_m_base);
219 KB_FREEALL(usf.usf_m_base);
226 * Send a SETUP request
228 * Build and send a Q.2931 SETUP message.
231 * usp pointer to UNISIG protocol instance block
232 * uvp pointer to VCCB for which the request is being sent
239 unisig_send_setup(struct unisig *usp, struct unisig_vccb *uvp)
242 struct unisig_msg *setup;
243 Atm_attributes *ap = &uvp->uv_connvc->cvc_attr;
245 ATM_DEBUG1("unisig_send_setup: uvp=%p\n", uvp);
248 * Make sure required connection attriutes are set
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) {
261 * Get memory for a SETUP message
263 setup = (struct unisig_msg *)atm_allocate(&unisig_msgpool);
270 * Fill in the SETUP message
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;
278 * Set IEs from connection attributes
280 err = unisig_set_attrs(usp, setup, ap);
285 * Attach a Calling Party Number IE if the user didn't
286 * specify one in the attribute block
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) {
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);
304 * Send the SETUP message
306 err = unisig_send_msg(usp, setup);
310 unisig_free_msg(setup);
317 * Send a RELEASE message
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
333 unisig_send_release(struct unisig *usp, struct unisig_vccb *uvp,
334 struct unisig_msg *msg, int cause)
337 struct unisig_msg *rls_msg;
338 struct ie_generic *cause_ie;
340 ATM_DEBUG2("unisig_send_release: usp=%p, uvp=%p\n",
344 * Get memory for a RELEASE message
346 rls_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
347 if (rls_msg == NULL) {
350 cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
351 if (cause_ie == NULL) {
357 * Fill in the RELEASE message
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;
366 * Fill out the cause IE
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);
373 cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
374 unisig_cause_from_msg(cause_ie, msg, cause);
380 err = unisig_send_msg(usp, rls_msg);
381 unisig_free_msg(rls_msg);
388 * Send a RELEASE COMPLETE message
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
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
402 * errno error encountered
406 unisig_send_release_complete(struct unisig *usp, struct unisig_vccb *uvp,
407 struct unisig_msg *msg, int cause)
410 struct unisig_msg *rls_cmp;
411 struct ie_generic *cause_ie;
413 ATM_DEBUG4("unisig_send_release_complete usp=%p, uvp=%p, msg=%p, cause=%d\n",
414 usp, uvp, msg, cause);
417 * Get memory for a RELEASE COMPLETE message
419 rls_cmp = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
420 if (rls_cmp == NULL) {
423 cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
424 if (cause_ie == NULL) {
430 * Fill in the RELEASE COMPLETE message
433 rls_cmp->msg_call_ref = uvp->uv_call_ref;
435 rls_cmp->msg_call_ref = EXTRACT_CREF(msg->msg_call_ref);
437 rls_cmp->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL;
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;
445 * Fill out the cause IE
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);
452 cause_ie->ie_caus_loc = UNI_IE_CAUS_LOC_USER;
453 unisig_cause_from_msg(cause_ie, msg, cause);
457 * Send the RELEASE COMPLETE
459 err = unisig_send_msg(usp, rls_cmp);
460 unisig_free_msg(rls_cmp);
467 * Send a STATUS message
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
474 * msg pointer to the message which triggered the send
475 * cause the cause code to include in the message
482 unisig_send_status(struct unisig *usp, struct unisig_vccb *uvp,
483 struct unisig_msg *msg, int cause)
486 struct unisig_msg *stat_msg;
487 struct ie_generic *cause_ie, *clst_ie, *iep;
489 ATM_DEBUG4("unisig_send_status: usp=%p, uvp=%p, msg=%p, cause=%d\n",
490 usp, uvp, msg, cause);
493 * Get memory for a STATUS message
495 stat_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
496 if (stat_msg == NULL) {
499 cause_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
500 if (cause_ie == NULL) {
504 clst_ie = (struct ie_generic *) atm_allocate(&unisig_iepool);
505 if (clst_ie == NULL) {
512 * Fill in the STATUS message
515 stat_msg->msg_call_ref = uvp->uv_call_ref;
517 stat_msg->msg_call_ref =
518 EXTRACT_CREF(msg->msg_call_ref);
520 stat_msg->msg_call_ref = UNI_MSG_CALL_REF_GLOBAL;
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;
529 * Fill out the call state IE
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;
536 clst_ie->ie_clst_state = uvp->uv_sstate;
538 clst_ie->ie_clst_state = UNI_NULL;
542 * Fill out the cause IE
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;
551 case UNI_IE_CAUS_MTEXIST:
552 case UNI_IE_CAUS_STATE:
554 cause_ie->ie_caus_diagnostic[0] = msg->msg_type;
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] =
571 * Send the STATUS message
573 err = unisig_send_msg(usp, stat_msg);
574 unisig_free_msg(stat_msg);
581 * Process a RESTART message
584 * usp pointer to UNISIG protocol instance block
585 * msg pointer to the RESTART message
592 unisig_rcv_restart(struct unisig *usp, struct unisig_msg *msg)
594 struct unisig_vccb *uvp, *uvnext;
595 struct unisig_msg *rsta_msg;
597 ATM_DEBUG2("unisig_rcv_restart: usp=%p, msg=%p\n",
601 * Check what class of VCCs we're supposed to restart
603 if (msg->msg_ie_rsti->ie_rsti_class == UNI_IE_RSTI_IND_VC) {
605 * Just restart the indicated VCC
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,
612 if (uvp && uvp->uv_type & VCC_SVC) {
613 unisig_clear_vcc(usp, uvp,
614 T_ATM_CAUSE_NORMAL_CALL_CLEARING);
622 for (uvp=Q_HEAD(usp->us_vccq, struct unisig_vccb); uvp;
624 uvnext = Q_NEXT(uvp, struct unisig_vccb,
626 if (uvp->uv_type & VCC_SVC) {
627 unisig_clear_vcc(usp, uvp,
628 T_ATM_CAUSE_NORMAL_CALL_CLEARING);
635 * Get memory for a RESTART ACKNOWLEDGE message
637 rsta_msg = (struct unisig_msg *) atm_allocate(&unisig_msgpool);
638 if (rsta_msg == NULL) {
643 * Fill out the message
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;
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);
667 * Process a SETUP message
670 * usp pointer to UNISIG protocol instance block
671 * msg pointer to the SETUP message
678 unisig_rcv_setup(struct unisig *usp, struct unisig_msg *msg)
680 struct unisig_vccb *uvp = NULL;
681 struct ie_generic *iep;
683 ATM_DEBUG2("unisig_rcv_setup: usp=%p, msg=%p\n", usp, msg);
686 * If we already have a VCC with the call reference,
687 * ignore the SETUP message
689 uvp = unisig_find_conn(usp, EXTRACT_CREF(msg->msg_call_ref));
694 * If the call reference flag is incorrectly set,
695 * ignore the SETUP message
697 if (msg->msg_call_ref & UNI_MSG_CALL_REF_RMT)
701 * If there are missing mandatory IEs, send a
702 * RELEASE COMPLETE message and ignore the SETUP
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);
713 * If there are mandatory IEs with invalid content, send a
714 * RELEASE COMPLETE message and ignore the SETUP
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,
720 UNI_IE_CAUS_IECONTENT);
726 * Get a new VCCB for the connection
728 uvp = (struct unisig_vccb *)atm_allocate(&unisig_vcpool);
734 * Put the VCCB on the UNISIG queue
736 ENQUEUE(uvp, struct unisig_vccb, uv_sigelem, usp->us_vccq);
739 * Set the state and call reference value
741 uvp->uv_sstate = UNI_NULL;
742 uvp->uv_call_ref = EXTRACT_CREF(msg->msg_call_ref);
745 * Pass the VCCB and message to the VC state machine
747 unisig_vc_state(usp, uvp, UNI_VC_SETUP_MSG, msg);
750 * If the VCCB state is NULL, the open failed and the
751 * VCCB should be released
753 if (uvp->uv_sstate == UNI_NULL) {
754 DEQUEUE(uvp, struct unisig_vccb, uv_sigelem,
764 * Process a UNISIG signalling message
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.
771 * usp pointer to UNISIG protocol instance block
772 * m pointer to a buffer chain containing the UNISIG message
779 unisig_rcv_msg(struct unisig *usp, KBuffer *m)
784 struct unisig_msg *msg = 0;
785 struct unisig_vccb *uvp = 0;
786 struct ie_generic *iep;
788 ATM_DEBUG2("unisig_rcv_msg: bfr=%p, len=%d\n", m, KB_LEN(m));
791 unisig_print_mbuf(m);
795 * Get storage for the message
797 msg = (struct unisig_msg *)atm_allocate(&unisig_msgpool);
804 * Convert the message from network order to internal format
806 err = usf_init(&usf, usp, m, USF_DECODE, 0);
809 panic("unisig_rcv_msg: invalid parameter\n");
810 ATM_DEBUG1("unisig_rcv_msg: decode init failed with %d\n",
815 err = usf_dec_msg(&usf, msg);
817 ATM_DEBUG1("unisig_rcv_msg: decode failed with %d\n",
824 * Debug--print some information about the message
826 if (unisig_print_msg)
827 usp_print_msg(msg, UNISIG_MSG_IN);
831 * Get the call reference value
833 cref = EXTRACT_CREF(msg->msg_call_ref);
836 * Any message with the global call reference value except
837 * RESTART, RESTART ACK, or STATUS is in error
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) {
844 * Send STATUS message indicating the error
846 err = unisig_send_status(usp, NULL,
847 msg, UNI_IE_CAUS_CREF);
852 * Check for missing mandatory IEs. Checks for SETUP,
853 * RELEASE, and RELEASE COMPLETE are handled elsewhere.
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,
862 UNI_IE_CAUS_MISSING);
869 * Find the VCCB associated with the message
871 uvp = unisig_find_conn(usp, cref);
874 * Process the message based on its type
876 switch(msg->msg_type) {
878 unisig_vc_state(usp, uvp,
879 UNI_VC_CALLP_MSG, msg);
882 unisig_vc_state(usp, uvp,
883 UNI_VC_CONNECT_MSG, msg);
886 unisig_vc_state(usp, uvp,
887 UNI_VC_CNCTACK_MSG, msg);
890 unisig_rcv_setup(usp, msg);
893 unisig_vc_state(usp, uvp,
894 UNI_VC_RELEASE_MSG, msg);
898 * Ignore a RELEASE COMPLETE with an unrecognized
899 * call reference value
902 unisig_vc_state(usp, uvp,
903 UNI_VC_RLSCMP_MSG, msg);
907 unisig_rcv_restart(usp, msg);
912 unisig_vc_state(usp, uvp,
913 UNI_VC_STATUS_MSG, msg);
916 unisig_vc_state(usp, uvp,
917 UNI_VC_STATUSENQ_MSG, msg);
920 unisig_vc_state(usp, uvp,
921 UNI_VC_ADDP_MSG, msg);
924 unisig_vc_state(usp, uvp,
925 UNI_VC_ADDPACK_MSG, msg);
928 unisig_vc_state(usp, uvp,
929 UNI_VC_ADDPREJ_MSG, msg);
932 unisig_vc_state(usp, uvp,
933 UNI_VC_DROP_MSG, msg);
936 unisig_vc_state(usp, uvp,
937 UNI_VC_DROPACK_MSG, msg);
941 * Message size didn't match size received
943 err = unisig_send_status(usp, uvp, msg,
944 UNI_IE_CAUS_MTEXIST);
949 * Handle message errors that require a response
954 * Message size didn't match size received
956 err = unisig_send_status(usp, uvp, msg,
962 * Free the incoming message (both buffer and internal format)
966 unisig_free_msg(msg);