/***************************************************************************** @(#) $Id: mtp_sm.c,v 0.7.2.12 2000/10/05 10:23:04 brian Exp $ ----------------------------------------------------------------------------- Copyright (C) 1997, 1998, 1999, 2000 Brian Bidulock All Rights Reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. Last Modified $Date: 2000/10/05 10:23:04 $ by $Author: brian $ ----------------------------------------------------------------------------- $Log: mtp_sm.c,v $ Revision 0.7.2.12 2000/10/05 10:23:04 brian Some work on link management and test. Revision 0.7.2.12 2000/10/03 00:53:54 brian Some work on link management and test. Revision 0.7.2.11 2000/09/24 07:32:56 brian Added some link management. Revision 0.7.2.10 2000/09/24 06:30:55 brian Committing changes. Revision 0.7.2.9 2000/09/21 05:19:07 brian Removed some leftover files. Added changeback to mtp_sm.c. Revision 0.7.2.8 2000/09/20 04:35:56 brian Lots of work in mtp_sm.c to get changeover worked in. Revision 0.7.2.7 2000/09/18 09:33:44 brian A bunch of work in state machines. Revision 0.7.2.6 2000/09/13 13:47:06 brian A lot of work in state machine: haven't check compile yet, just wanting to save work for later. Revision 0.7.2.5 2000/09/12 18:45:22 brian Lots of work within the MTP state machine files. Revision 0.7.2.4 2000/09/12 04:57:30 brian Still working on state machine: still compiles. Revision 0.7.2.3 2000/09/11 23:41:53 brian Working on MTP state machine: still compiles. Revision 0.7.2.2 2000/09/11 20:20:48 brian Cleaned up routing structure. Revision 0.7.2.1 2000/09/11 14:53:01 brian State machines compile. Revision 0.7 2000/09/11 14:07:08 brian Added files for socket stuff and routing. Revision 0.7 2000/09/11 07:20:41 brian Addeds MTP state machine and mtp and sccp socket glue code. *****************************************************************************/ static char const ident[] = "$Name: Prerelease1 $($Revision: 0.7.2.12 $) $Date: 2000/10/05 10:23:04 $"; #include #include #include #include #include #include #include #include #include "mtp_parse.h" #include "af_ss7.h" #include "mtp_route.h" #include "mtp_sm.h" #include "../../include/linux/ss7link.h" #ifdef pvar #undef pvar #endif #define pvar ansi /* protocol variant: other choice: itu */ #define hdrlen 1+sizeof(struct __ansi_mtph) static int mtp_output(struct sk_buff *skb, struct ss7mtp_cb *mtp, struct ss7_routeset *rt); /* * A slightly different approach to state machine desing: the brute force * approach: take each MTP message and first determine it's routing by the * routing label and route it either remotely or locally. If the message is * local, tear the message down and decide whether it is a system-wide, * linkset-specific, or link-specific message and pass it to the function to * handle that particular message with that level's control block. */ static struct ss7mtp_cb deflt_addr = { NULL, { 0 }, 0x1, NULL, { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, NULL, NULL, 0, 0, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, 0U, NULL, NULL, NULL }; struct ss7mtp_cb *ss7mtp_all = &deflt_addr; static __inline struct sk_buff *mtp_alloc_skb(int gfp_mask) { struct sk_buff *skb; ss7mtp_msg *m = (ss7mtp_msg *)skb->nh.raw; if ( (skb = alloc_skb( 4 + hdrlen + sizeof(m->pvar.msg), gfp_mask )) ) { memset(skb->head, 0x0, skb->end-skb->head); skb_reserve(skb, 3); /* for L2 BSN/BIB FSN/FIB LI */ skb->nh.raw = skb->data + 1; skb->h.raw = skb->data - 2; skb->protocol = AF_SS7; skb->pkt_type = ETH_P_SS7; skb->priority = TC_PRIO_CONTROL; } return (skb); } /* 4.1.2 The diversion of traffic in cases of unavailability or availability or * restriction of signalling links and routes is typically made my means of the following * basic procedures, included in the signalling traffic management function: * * - signalling link unavailability (failure, deactivation, blocking or inhibiting): the * changeover procedures (see clause 5) is used to divert signalling traffic to one or * more alternative links (if any); * * - signalling link availability (restoration, activation, unblocking or uninhibiting): * the changeback procedure (see clause 6) is used to divert signalling traffic to the * link made available; * * - signalling route uavailability: the forced rerouting procedure (see clause 7) is * used to divert signalling traffic to an alternative route (if any); * * - signalling route availability: the controlled rerouting procedure (see clause 8) is * used to divert signalling traffic to the route made available; * * - signalling route restricted: the controlled rerouting procedure (see clause 8) is * used to diver signalling traffic to an alternative route (if any); * * - signalling point availability: the MTP restart procedure (see clause 9) is used to * divert the signalling traffic to (or via) the point made available. */ /* 4.3 Signalling link unavailability * * 4.3.1 When a signalling link becomes unavailable (see 3.2) signalling traffic carried * by the link is transferred to one or more alternative links by means of a changeover * procedure. The alternative link or links are determined in accordance with the * following criteria. * * 4.3.2 In the case when there is one or more alternative signalling links available in * the link set to which the unavailable link belongs, the signalling traffic is * transferred within the linkset to: * * a) an active and unblocked signalling link, currently not carrying any traffic. If no * such signalling link exists, the signalling traffic is transferred to: * * b) one or possibly more than one signalling link currently carrying traffic. In the * case of transfer to one signalling link, the alternative signalling link is that * having the highest priority of the signalling links in service. * * 4.3.3 In the case where there is no alternative signalling link within the link set * to which the unavailable signalling link belongs, the signalling traffic is transferred * to one or more alternative link sets (combined link sets) in accordance with the * alternative routing detailed for each destination. For a particular destination, the * alternative link set (combined link set) is the link set (combined link set) in service * having the highest priority. * * Within a new link set, signalling traffic is distributed over the signalling links in * accordance with the routing currently applicable for that links set; i.e., the * transferred traffic is routed the same way as the traffic already using the link set. */ /* 4.4 Signalling link availability * * 4.4.1 When a previously unavailable signalling link becomes available (see 3.2), * signalling traffic may be transferred to the available signalling link by means of the * changeback procedure. The traffic to be transferred is determined in accordance with * the following criteria. * * 4.4.2 In the case when the link set, to whcih the available signalling link belongs, * already carries signalling traffic on other signalling links in the link set, the * traffic to be transferred includes the traffic for which the available signalling link * is the normal one. Note that the assignment of the normal traffic to a signalling link * may be changed during the changeback process taking into account, for example, system * performance. * * The normal traffic is transferred from on or more signalling links, depending on the * criteria applied when the signalling link became unavailable (see 4.3.2), and upon the * criteria applied if any of the alternative siginalling link(s) themselves became * unavailable, or available, in the meantime. * * If signalling links in the linkset are still unavailable, and if it is required for * load balancing purposes, signalling traffic extra to that normally carried by any link * might also be identified for diversion to the signalling link made available, and to * other available signalling links in the linkset. * * The extra traffic is transferred from one or more signalling links. * * 4.4.3 In the case when the link set (combined link set) to which the available * signalling links belong, does not carry any signalling traffic [i.e. a link set * (combined link set) has become available], the traffic to be transferred is the traffic * for which the avilable link set (combined link set) has higher priority than the linkk * set (combined link set) currently used. * * The traffic is transferred from one or more link sets (combined link sets) and from one * or more signalling links within each link set. * * 4.5 Signalling route unavailability * * When a signalling route becomes unavailable (see 3.4), signalling traffic currently * carried by the unavailable route is transferred to an alternative route by means of * forced re-routing procedure. The alternative route (i.e. the alternative link set or * link sets) is determined in accordance with the alternative routing defined for the * concerned destination (see.4.3.3). * * 4.6 Signalling route availability * * When a previously unavailable signalling route becomes available again (see 3.4), * signalling traffic may be transferred to the available route by means of a controlled * rerouting procedure. This is applicable in the case when the available route (link * set) has higher priority than the route (link set) currently used for traffic for the * concerned destination (see 4.4.3). * * The transferred traffic is distributed over the links of the new link set in accordance * with the routing currently applicable for that link set. * * 4.7 Signalling route restriction * * When a signalling route becomes restricted (see 3.4), signalling traffic carried by the * restricted route is, if possible, transferred to an alternative route by means of the * controlled rerouting procedure, if an equal priority alternative is available and not * restricted. The alternative route is determined in accordance with alternate routing * detailed for the concerned destination (see 4.3.3). * * 4.8 Signalling point avialability * * When a previous unavailable signalling point becomes available (see 3.6), signalling * traffic may be transferred to the available point my means of the MTP restart procedure * (see clause 9). */ /* * Tell all bound mtp users of point code availability change. */ static __inline void mtp_resume(struct ss7mtp_cb *mtp, struct ss7_routeset *rs) { struct sock *sk; int i; (void)rs; for ( i = 0 ; i < 16 ; i++ ) if ( (sk = mtp->sks[i]) ) /* found bound user */ ; /* FIXME: make me work! */ } /* * Tell all bound mtp users of point code availability change. */ static __inline void mtp_pause(struct ss7mtp_cb *mtp, struct ss7_routeset *rs) { struct sock *sk; int i; (void)rs; for ( i = 0 ; i < 16 ; i++ ) if ( (sk = mtp->sks[i]) ) /* found bound user */ ; /* FIXME: make me work! */ } /* * Tell all bound mtp users of congestion status change. */ static __inline void mtp_status(struct ss7mtp_cb *mtp, struct ss7_routeset *rs) { struct sock *sk; int i; (void)rs; for ( i = 0 ; i < 16 ; i++ ) if ( (sk = mtp->sks[i]) ) /* found bound user */ ; /* FIXME: make me work! */ } /* * Timeouts: */ static __inline void link_output(struct sk_buff *skb, struct ss7_link *link); static __inline void link_out_of_service(struct ss7_link *link); static void mtp_t2t_timeout(unsigned long data); /* * The remote MTP failed to respond to an SLTM. Only give * it two tries and then fail the link. */ static void mtp_t1t_timeout(unsigned long data) { struct ss7_link *link = (struct ss7_link *)data; del_timer(&link->t2t); if ( link->flags & SS7_LINK_RETEST ) { struct sk_buff *skb; if ( (skb = mtp_alloc_skb(GFP_KERNEL)) ) { *(skb->data) = SS7_L2_STOP; skb->priority = TC_PRIO_CONTROL; __skb_trim(skb, 1); link_output(skb, link); } link_out_of_service(link); } else { link->flags |= SS7_LINK_RETEST; mtp_t2t_timeout(data); } } /* * Time to send another SLTM on the link. */ static __inline void send_sltm(struct ss7_link *link); static void mtp_t2t_timeout(unsigned long data) { struct ss7_link *link = (struct ss7_link *)data; if ( !(link->flags & SS7_LINK_DONTUSE) ) send_sltm(link); } static __inline void changeover_divert(struct ss7_link *link); static __inline void changeback_divert(struct ss7_link *link); /* * Completion of time-controlled changeover procedure on expiry of timer T1. * Ignore buffer updating and retrieval (purge the retrieval buffer) and * perform immediate changeover diversion, in accordance with Q.704(07/96) * 5.6.2. */ static void mtp_t1_timeout(unsigned long data) { struct ss7_link *link = (struct ss7_link *)data; if ( link->cob_state != SS7_LK_COB_TIME_CONTROLLED ) return; skb_queue_purge(&link->rtrvb); changeover_divert(link); } /* * Completion of normal changeover procedure in the event that an * acknowledgement is not received, ignore buffer updating and retrieval * (purge the retrieval buffer) and perform immediate changeover diversion, * in accordance with Q.704 (07/96) 5.7.2. */ static void mtp_t2_timeout(unsigned long data) { struct ss7_link *link = (struct ss7_link *)data; if ( link->cob_state != SS7_LK_COB_WAITING_ACK ) return; skb_queue_purge(&link->rtrvb); changeover_divert(link); } /* * Completion of time-controlled changeback procedure on expiry of timer T3. * Perform immediate changeback diversion, in accordance with Q.704 (07/96) * 6.4.2. */ static void mtp_t3_timeout(unsigned long data) { struct ss7_link *link = (struct ss7_link *)data; if ( link->cob_state != SS7_LK_COB_TIME_CONTROLLED ) return; changeback_divert(link); } /* * T4 Timeout waiting for COO/ECO ack. Send a second time and wait T5 per * Q.704 (07/96) 6.5.3. */ static __inline ss7_link *alt_link(struct ss7_link *link); static void mtp_t5_timeout(unsigned long data); static void mtp_t4_timeout(unsigned long data) { struct ss7_link *link = (struct ss7_link *)data; struct ss7mtp_cb *mtp = link->linkset->local->cb; if ( link->cob_state != SS7_LK_COB_WAITING_ACK ) return; del_timer(&link->t); link->t.data = (unsigned long)link; link->t.function = &mtp_t5_timeout; link->t.expires = jiffies + mtp->t5_value; add_timer(&link->t); if ( link->skb ) { struct ss7_link *alt = alt_link(link); if ( alt ) link_output(link->skb, link->alt); else kfree_skb(link->skb); link->skb = NULL; } } /* * T5 timeout waiting second time for COO/ECO ack. Inform maintenance and * divert traffic to recovered link immediately, per Q.704 (07/96) 6.5.3. */ static void mtp_t5_timeout(unsigned long data) { struct ss7_link *link = (struct ss7_link *)data; if ( link->cob_state != SS7_LK_COB_WAITING_ACK ) return; changeback_divert(link); } /* * Completion of controlled re-routing procedure. Restart traffic on * alternative route per Q.704 (07/86) 8.2.1 (c). */ static void mtp_t6_timeout(unsigned long data) { struct ss7_route *rt = (struct ss7_route *)data; struct sk_buff *skb; rt-> flags &= ~SS7_RT_CONTROLLEDRR; while ( skb_queue_len(&rt->ccrb) ) { skb = skb_dequeue(&rt->ccrb); mtp_output(skb, rt->linkset->local->cb, rt->routeset); } } /* * TFP wait standoff timer. Do not send responsive TFP during TFP wait * period as per Q.704 (07/96) 13.2.2. */ static void mtp_t8_timeout(unsigned long data) { struct ss7_routeset *rs = (struct ss7_routeset *)data; rs-> flags &= ~( SS7_RS_TFPWAIT ); } /* * Resend signalling-route-set-test message to prohibited or restricted * destinations every T10 as per Q.704 (07/96) 13.5.2 and 13.5.3. */ static void mtp_t10_timeout(unsigned long data) { struct ss7_route *rt = (struct ss7_route *)data; struct sk_buff *skb; struct ss7mtp_cb *mtp; if ( !rt->skb ) return; if ( !rt-> flags & SS7_RT_RSTEST ) /* test cancelled */ goto t10_cut_and_run; if ( !( skb = skb_clone(rt->skb, GFP_KERNEL) )) goto t10_cut_and_run; if ( (mtp = rt->routeset->cb) ) { mtp->output(skb, mtp, NULL); del_timer(&rt->t); /* go around again */ rt-> t.data = (unsigned long)rt; rt-> t.function = &mtp_t10_timeout; rt-> t.expires = jiffies + mtp->t10_value; add_timer(&rt->t); /* go around again */ return; } t10_cut_and_run: if ( rt->skb ) kfree_skb( rt->skb ); rt->skb = NULL; return; } /* * Perform T15 timeout procedure for signalling-route-set- congestion-test as * per Q.704 (07/96) 13.7.4, 13.7.5 and 13.9.4 (i). */ static void mtp_t16_timeout(unsigned long data); static void mtp_t15_timeout(unsigned long data) { struct ss7_routeset *rs = (struct ss7_routeset *)data; struct ss7mtp_cb *mtp = rs-> cb; if ( !rs->skb ) return; if ( !( rs-> flags & SS7_RS_CONGESTED ) || rs-> flags & SS7_RS_DONTUSE ) goto t15_free_and_go; rs-> t.data = (unsigned long)rs; rs-> t.function = &mtp_t16_timeout; rs-> t.expires = jiffies + mtp->t16_value; mtp_t16_timeout(rs->t.data); /* trigger t16 */ return; /* message is prebuilt */ t15_free_and_go: if ( rs->skb ) kfree_skb( rs->skb ); rs->skb = NULL; return; } /* * Perform T16 timeout procedure for signaling-route-set- congestion-test as * per Q.704 (07/96) 13.9.3, and 13.9.4 (ii). */ static void mtp_t16_timeout(unsigned long data) { struct ss7_routeset *rs = (struct ss7_routeset *)data; struct sk_buff *skb0, *skb = rs-> skb; struct ss7mtp_cb *mtp = rs-> cb; ss7mtp_msg *m; if ( !skb ) return; if (( !rs-> flags & SS7_RS_CONGESTED )||( rs-> flags & SS7_RS_DONTUSE )) goto t16_free_and_go; m = (ss7mtp_msg *)skb->nh.raw; if ( rs-> cong_status > m-> pvar.mh.mp ) { /* message got thru at last mp */ rs-> cong_status = m-> pvar.mh.mp; mtp_status(mtp,rs); /* inform users */ } if ( !( rs-> cong_status ) ) { /* we're done */ rs-> flags &= ~SS7_RS_CONGESTED; goto t16_free_and_go; } m-> pvar.mh.mp = rs-> cong_status - 1; /* test next lower */ if ( (skb0 = skb_clone(skb, GFP_KERNEL)) ) mtp_output( skb0, mtp, rs ); del_timer(&rs->t); rs-> t.data = (unsigned long)rs; rs-> t.function = &mtp_t16_timeout; rs-> t.expires = jiffies + mtp->t16_value; add_timer(&rs->t); /* go around again */ return; t16_free_and_go: if ( rs->skb ) kfree_skb( rs->skb ); rs->skb = NULL; return; } /* * Perform T17 timeout procedure for signalling link, attempt to restore link * again per Q.704 (07/96) 12.2.2. */ static void mtp_t17_timeout(unsigned long data) { struct ss7_link *link = (struct ss7_link *)data; struct sk_buff *skb; if (!link-> flags & SS7_LINK_OUT_OF_SERVICE) return; if ( (skb = mtp_alloc_skb(GFP_KERNEL)) ) { /* * Attempt restoration again per Q.704 (07/96) 12.2.2. */ skb->data[0] = SS7_L2_START; skb->priority = TC_PRIO_CONTROL; __skb_trim(skb,1); link_output(skb, link); } else { /* * Not much to do without buffer except restart T17 timer and attempt * restoration on next timeout. */ struct ss7mtp_cb *mtp = link->linkset->local->cb; del_timer(&link->t); link->t.data = data; link->t.function = &mtp_t17_timeout; link->t.expires = jiffies + mtp->t17_value; add_timer(&link->t); } return; } static void mtp_t18_timeout(unsigned long data) { (void)data; (void)&mtp_t18_timeout; } static void mtp_t19_timeout(unsigned long data) { (void)data; (void)&mtp_t19_timeout; } static void mtp_t20_timeout(unsigned long data) { (void)data; (void)&mtp_t20_timeout; } /* * Timer for adjacent MTP restart. This timer is cancelled * by the receipt of a TRA from adjacent signalling point. * Upon expiry perform route allowed procedure for all * routes which use linkset directly attached to adjacent * signalling point. Start time-controlled changeback * procedure for all available links in the direct linkset * to the restarting MTP. */ static void mtp_t21_timeout(unsigned long data) { struct ss7_routeset *adj = (struct ss7_routeset *)data; (void)&mtp_t21_timeout; del_timer(&adj->tmr); if ( !(adj-> flags & SS7_RS_MTP_RESTART ) ) return; adj-> flags &= ~SS7_RS_MTP_RESTART; /* FIXME: for each link in each linkset terminating on * the restarting MTP which was restored during the MTP * Restart procedure, start time-controlled changeback. * This will broadcast TFA, TFP, and TFR as required. */ } /* * As a basis of the restart procedure it is assumed that most of the * signalling points within the network are accessible. Thus, at the * beginning of the restart procedure, all concerned routes are considered to * be allowed, and the update of the network status is performed by the * exchange of transfer-prohibited (TFP) and/or transfer-restricted (TFR) * messages. * * The MTP restart procedure uses the Traffic Restart Allowed (TRA) message * which contains: * * - the lable, indicating the originating singalling point and the * adjacent destination signalling point * * - the traffic restart allowed signal * * The format and coding of this message appear in clause 15. * * When the adjacent node has finished sending all relevant TFP and/or TFR * messages to the node with the restarting MTP, it finalling sends a TFA * message which indicates that all relevant routing information has been * transferred. Thus, at the node with the restarting MTP, the number of * received TRA messages is an indication of the completeness of the routing * data. * * When the restarting MTP has completed all actions or when the overall * restart time is over, it sends TRA messages directly to all of its * adjacent nodes acessible via a direct link set. These messages indicate * that the restart procedure is terminated and User traffic should be * started. * * 9.2 Actions in a signalling point whose MTP is restarting * * 9.2.1 A signalling point starts the MTP restart procedure when its first * link is in service at level 2. The restarting MTP: * * - if it has the transfer function starts a timer T18; * * - starts overall restart timer T20; and, * * - continues activating or unblocking all of its signalling links by * means of the basic signalling link management procedures (see 12.2) * * NOTE - In order to use the overall restart time in an efficient way, it is * preferrable to make all link sets available at nearly the same time, by * activating first one link per link set, and by applying emergency * alignment for at least the first link in each link set. Because of this * measure, the routing data update can be started for all rroutes at the * very beginning of the restart procedure. * * 9.2.2 If the signalling point's restarting MTP has the transfer * function, the MTP restart procedure consists of two phases. Within the * first phase, supervised by timer T18, links are activated and the routing * tables within the restarting MTP are updated according to the transfer- * prohibited, transfer-allowed and transfer-restricted messages (see clause * 15) received from the adjacent nodes. in addition, the restarting MTP * takes into account any traffic restart allowed messages received from * adjacent routes. Timer T18 is implementation and network dependent, and * is stopped when: * * 1) sufficient links and link sets are available to carry the expected * signalling traffice; and, * * 2) enough TRA messages (and therefore routing data) has been received to * give a high level of confidence in the MTP routing tables. * * NOTE - In normal circumstances the restarting MTP should wait fro TRA * messages from all adjacent nodes. There are, however, other situations * where this might not be useful, e.g. for a long-term equipment failure. * * When T18 stops or expires, the second phase begins, which includes as a * major part a broadcast fo non-preventive transfer prohibited messages * [i.e. those TFPs according to 13.2.2 v)] and transfer-restricted messages, * taking into account signalling link sets which are not available and any * TFP, TFA and TFR messages received during phase 1. Note that timer T18 is * determined such that during phase 2 the broadcast of TFP and TFR messages * may be completed in normal situations. * * TRA messages received during phase 2 should be ignored. If during phase 2 * a destination has been declared to be inaccessible by sending of a TFP * message, and afterwards, but still within phase 2, this destination * becomes accessible to the restarting MTP by reception of a TFA or TFR * message or the availability of a corresponding link , this new * accessibility is a late event and should be treated outside the restart * procedure. The handling of new accessibility of the said destination * before the sending of a TFP referring to that destination is an * implementation dependent matter. * * When all TFP and TFR messages have been sent, the overall restart timer * T20 is stopped and phase 2 is finished. Note that preventative TFP * messages [i.e. those according to 13.2.2 i)], except possibly those for * highest priority routes, must have been sent before normal User traffic is * carried. This migh be done during or after phase 2. * * 9.2.3 If the restarting MTP has no transfer function, phase 1 (see * 9.2.2) but not phase 2 is present. In this case, the whole restart time * is available for phase 1. The overall restart timer T20 is stopped when: * * 1) sufficient links and link sets are avialable to carry the expected * signalling traffic; and, * * 2) enough TRA messages (and therefore routing data) have been received to * give a high level of confidence in the MTP routing tables. * * 9.2.4 When T20 is stopped or expires, the restarting MTP of the * signalling point or signalling transfer point sends traffic restart * allowed message to all adjacent signalling points via corresponding * available direct link sets, and an indication of the end of the MTP * restart is sent to all local MTP Users showing each signalling point's * accessibility or inaccessibility. The means of doing the later is * implementation dependent. * * In addition, timer T19 is started (see 9.5.2) for all signalling points to * which a TRA message has just been sent. Normal operation is then resumed. * * When T20 expires the transmission of TFP and TFR messages is stopped. * However, preventive TFP messages [i.e. those according to 13.2.2 i)] * except possibly those for highest priority routes, must have been sent * before MTP User traffic is restarted. * * 9.3 Actions in a signalling point X, adjacent to a signalling point Y * whose MTP restarts * * 9.3.1 A signalling point X considers that the MTP of an inaccessible * signalling point Y is restarting when: * * - the first link in a direct link set is in the "in service" state at * level 2; or * * - another route becomes available due either to reception of a * corresponding TFA, TFR or TRA message, or by the corresponding link * set becoming available (see 3.6.2.2). * * 9.3.2 When the first link in a direct link set towards signalling point * Y, whose MTP is restarting, is in the "in service" state a level 2, * signalling point X restarts timer T21 and takes account of any TFP, TFA * and TFR messages received from signalling point Y. In addition X takes * the following action: * * - if X has the transfer function, when the direct link set is available * at level 3, X sends any necessary TFP and TFR messages to Y; then * * - X sends a traffic restart allowed message to signalling point Y. * * If a signalling point, previously declared to be inaccessible, becomes * available again before T21 is stopped or expires, a corresponding TFA or * TFR message is sent to the signalling point Y whose MTP is restarting. * * If a signalling point becomes prohibited or restricted to signalling point * X after a TRA message has been sent by X to Y, X sends a corresponding TFP * or TFR message to Y. * * When a traffic restart allowed message has been received by X from * signalling point Y, and a TRA message has been sent by X to Y, X stops * timer T21. * * Note that preventive TFP messages according to 13.2.2 i) must be sent * before MTP User traffic is restarted. * * NOTE - This includes the case where the MTP of Y is restarting as well as * the case that both X and Y start the adjacent signalling point MTP restart * procedure at the new availability of the incoming direct link set. In the * latter case, one side will received a TRA message from the other while * still sending TFP and/or TFR messages, so that is has not yet sent its TRA * messages. The transmission of routing information should be completed * before this TRA message is sent to the adjacent node and timer T21 * stopped. * * When T21 is stopped or expires, signalling point X sends an MTP-RESUME * primitive concerning Y, and all siginialling points made available via Y, * to all local MTP Users. If X has the transfer function, it broadcasts to * adjacent signalling points transfer-allowed and/or transfer restricted * messages concerning Y and all signalling points made accessible via Y. * * Note that preventive TFPs according to 13.2.2 i) must be sent before MTP * User traffic is restarted. * * In the abnormal case where transfer prohibited and transfer restricted * messages are still being sent to Y when T21 expires (and hence no TRA * message has yet been sent to Y), such routing data transmission is stopped * and no TRA message is sent to Y. Note that preventive TFPs according to * 13.2.2 i) must still be sent during the changeback procedure. * * 9.3.3 When signalling point Y becomes accessible by means other than via * a direct link set between X and Y, X sends an MTP-RESUME primitive * concerning Y to all local MTP Users. In addition, if signalling point X * has the transfer function, X sends to Y any required transfer-prohibited * and transfer-restricted emssages on the available route. X then * broadcasts TFA and/or TFR messages (see clause 13) concerning Y. Note * that X should not in this case alter any routing data other than that for * Y. * * 9.4. Short term isolations * * 9.4.1 In the case where a signalling point is isolated due to a short * term processor outage [lasting less than T1 (see 16.8)] occuring on some * or all of its links at nearly the same time, the restart procedure should * not be started. * * If an isolation lasts longer that T1, the restart procedure must be * performed. * * 9.4.2 When a destination Y becomes inacessible, and routing control * finds an inhibited link within the route set to Y, a signalling routing * control initiated uninhibiting action is performed (see 10.3). If at * least one inhibited link is in the level 2 "in service" state, and * uninhibiting is successful, the isolation will be of short term and no * restart procedure should be performed on either side of the link. * * 9.5. TRA message and timer T19 * * 9.5.1 If a signalling point X receives an unexpected TRA message from an * adjacent node Y and no associated T19 timer is running, X sends to Y any * necessary TFP and TFR messages if X has the transfer function, and a TRA * message to Y. In addition, X starts a timer T19 associated with Y. * * 9.5.2 If a signalling point receives a TRA message from an adjacent node * and an associated timer T19 is running, this TRA is discarded and no * further action is necessary. * * 9.6 General rules * * 9.6.1 When the MTP of a signalling point restarts, it considers at the * beginning of the MTP restart procedure all signalling routes to be * allowed. * * 9.6.2 After the MTP of an adjacent node X has restarted, and if T21 has * been started (see 9.3.2), all routes using X are considered to be * available unless corresponding TFP or TFR messages have been received * whilst T21 was running. * * 9.6.3 A signalling route set test message received in a restarting MTP * is ignored during the MTP restart procedure. * * Signalling route set test messages received in a signalling point adjacent * to signalling point Y whose MTP is restarting before T21 expires are * handled, but the relies assume that all signalling routes using Y are * prohibited. * * 9.6.4 Late events, i.e. link restorations or reception of TFA or TFR * messages, occuring in phase 2 at a node whose MTP is restarting after the * node has send out TFPs or TFRs referring to the concerned signalling * points, are treated outside the restart procedure as normal events. * * Handling of late events in phase 2 before sending out TFPs or TFRs * referring to the concerned signalling points is an implementation * dependent matter. In addition, it is an implementation dependent matter * whether the reception of TFPs or link set failures during phase 2 are * handled within or after the terminaiton of the restart procedure. * * 9.6.5 When an adjacent signalling point Y becomes accessible on receipt * of a TFA, TFR or TRA message (see 3.6.2), the concerned signalling point * peforms controlled rerouting towards Y. * * 9.6.6 All messages to another destination received at a signalling point * whose MTP is restarting are discarded. * * All messages received during the restart procedure concerning a local MTP * User (servvice indication != 0000 and != 0001) are discarded. * * All messages received with service indicator = 0000 in a restarting MTP * for the signalling point itself are treated as described in the MTP * restart procedure. Those messages not described elsewhere in the * procedure are discarded and no further action is taken on them (message * groups CHM, ECM, FCM, RSM, UFC, MIM and DLM). * * 9.6.7 In adjacent signalling points during the restart procedure, * messages not part of the restart procedure but which are destined to or * through the signalling point whose MTP is restarting, are discarded. * * Messages received with service indicator = 0001 are handled normally * during the restart procedure. * * 9.6.8 If a gateway node's MTPs are restarting in multiple networks, it * may be of advantage to coordinate their restarting procedrues * (implementation dependent). * * 9.7.1 SP with restarting MTP according to subclause 9.2 * * All links unavailable (e.g., LPO) * time > T1 * First link in service at level 2. * if (mtp->transfer) { * start T18 * } * start T20 * Accept TFP, TFR, TRA messages. * Accept TFA or TFR negating previous TFP. * Sufficient links available. * Accept TFP, TFR, TRA messages. * Accept TFA or TFR negating previous TFP. * Enough TRA messages received or T18 empty. * if (mtp->transfer) * while (T20 still running) { * TFP, TFR broadcast. * Accept late availability of link, TFP, TFR or TFA received. * Last TFP, TFR or T20 expiry, then break. * } * else * while (T20 still running) { * Accept late availability of link, TFP, TFR or TFA received. * Enough TRAs received or T20 expiry, then break. * } * TRA broadcast over direct link sets * Set T19 for each TRA broadcast * MTP-RESUME indications to MTP Users. * if (mtp->transfer) * Send TFAs, TFPs, TFRs broadcast due to late events. * * * 9.7.2 Actions in SP X adjacent to SPY whose MTP restarts according to * subclause 9.3 * * All links to Y unavailable (e.g. LPO) * time > T1 * First link in direct link set to Y in service at level 2 * Start T21 * if (mtp->transfer) { * When first link in direct link set is available at level 3, send * TFP and TFR messages to Y. * } * Send TRA to Y. * if (mtp->transfer) { * while T21 still running, send TFA, TFP, TFR messages to Y because * of recent events. * } * Accept TFP, TFR messages from Y. * Receive TRA from Y or T21 expiry. * send MTP-RESUME indications wrt. Y and all SPs now accessible due to Y * to MTP Users. * if (mtp->transfer) { * broadcast TFA, TFR referring to Y and all SPs acessible via Y. * } */ /* * Link Output Function. * * Sends buffer to link using link's output method (if any). This function * consumes the sk_buff. */ static __inline void link_output(struct sk_buff *skb, struct ss7_link *link) { skb-> dev = link-> dev; if ( link->output ) link->output(skb); else dev_queue_xmit(skb); } /* * Message Output Function. * * This function is only invoked by the socket interface (and internal * management sending management messages) and is used for sending messages * outside the box. The transfer function is separated because it responds * on problems to the originator: this function responds to the local MTP. */ static int mtp_output(struct sk_buff *skb, struct ss7mtp_cb *mtp, struct ss7_routeset *rt) { ss7mtp_msg *m = (ss7mtp_msg *)skb->nh.raw; struct ss7_addr dest = { m->pvar.mh.rl.dpc }; unsigned mp = m->pvar.mh.mp; unsigned sls = m->pvar.mh.rl.sls; struct ss7_route *route; struct ss7_link *link; if ( !(rt) && !(rt = ss7_rt(dest)) ) { kfree_skb(skb); return -EHOSTUNREACH; } if ( rt-> type & SS7_RST_LOCAL ) { kfree_skb(skb); return -ENODEV; } if ( rt->flags & SS7_RS_DONTUSE ) { kfree_skb(skb); return -EHOSTDOWN; } if ( rt-> type & SS7_RST_INTERNAL ) { rt->cb->input(rt->cb, skb); return 0; } /* 13.7.2 A tranfser-controlled message relating to a given destination X is sent from a * signalling transfer point Y in response to a received message originating from * signalling point Z destined to signalling point X when the congestion priority of the * concerned message is less than the current congestion status of the signalling link * selected to transmit the concerned message from Y to X. * * In this case, the transfer-controlled message is sent to the originating point Z with * the congestion status filed set to the current congestion status of the signalling * link. */ route = ss7_select_rt( rt ); if ( route-> flags & SS7_RT_CONTROLLEDRR ) { skb_queue_tail(&route->ccrb, skb); return(0); } link = ss7_select_link(route, sls); if ( link-> flags & ( SS7_LINK_CHANGEOVER | SS7_LINK_CHANGEBACK ) ) { skb_queue_tail(&link->cocbb, skb); return(0); } if ( link-> flags & SS7_LINK_CONGESTED && mp < link->cong_status ) { kfree_skb(skb); return -EBUSY; } /* remind user */ link_output(skb,link); return (0); } static __inline struct ss7_link *find_link(__u32 adjcaddr, __u8 slc) { struct ss7_addr adjc = { adjcaddr }; struct ss7_routeset *adj; struct ss7_route *rt; struct ss7_linkset *ls; struct ss7_link *lc; if ( !(adj = ss7_rt(adjc)) ) return NULL; /* stray message */ if ( !(rt = adj->routes) ) return NULL; /* broken datastructure */ if ( !(ls = rt->linkset) ) return NULL; /* broken datastructure */ if ( !(lc = ls->links[slc]) ) return NULL; /* non-existent link */ return (lc); } /* * Perform the actions and procedure necessary upon receipt of a changeover * order (or emergency changeover order) in accordance with Q.704 (07/96) 5.4 * and 5.6. */ static __inline void send_changeover_ack(struct sk_buff *skb, struct ss7_link *link) { struct ss7mtp_cb *mtp = link->linkset->local->cb; struct sk_buff *skb0 = NULL; ss7mtp_msg *m = (ss7mtp_msg *)skb->nh.raw; unsigned slc = m->pvar.mh.rl.sls; /* * If we are already performing a changeover, either switch to an ack * mode and perform BSNT retrieval or send an ECA if we have already sent * an COO/ECO ourselves. Roughly per Q.704 (07/96) 5.4.1 and 5.6.2. */ if ( link->flags & ( SS7_LINK_CHANGEOVER | SS7_LINK_DONTUSE ) ) { /* * If we are performing a time-controlled changeover procedure, * switch to the normal changeover procedure on reception of a * changeover order in accordance with ``advantageous'' procedure in * Q.704 (07/96) 5.6.2. */ if ( link->cob_state == SS7_LK_COB_TIME_CONTROLLED ) if ( link->t.next ) { del_timer(&link->t); goto send_coa; } /* * If we are performing a normal or emergency changeover and have * already issued the changover order, respond with an emergency * changeover. If we are performing BSNT retrieval, switch to the * ack mode from the order mode and await the BSNT retrieval. Not * detailed in Q.704 but Q.704 (07/96) 5.4.1 and 5.6.2 state that we * must ``always'' return an acknowledgement to an order to permit * the remote end to complete. */ if ( link->cob_state == SS7_LK_COB_BSNT_REQ_COO ) { link->cob_state = SS7_LK_COB_BSNT_REQ_COA; return; } if ( skb0 || (skb0 = skb_clone(skb, GFP_KERNEL)) ) { m = (ss7mtp_msg *)skb0->nh.raw; m->pvar.mh.si = 0x0; /* snmm */ m->pvar.mh.ni = mtp->ni; m->pvar.mh.mp = 0x3; m->pvar.mh.rl.dpc = link->linkset->adjacent->addr; m->pvar.mh.rl.opc = link->linkset->local->addr; m->pvar.mh.rl.sls = slc; m->pvar.mh.h0 = 0x2; /* ecm */ m->pvar.mh.h1 = 0x2; /* eca */ *(skb0->data) = SS7_L2_PDU; skb0->priority = TC_PRIO_BESTEFFORT; __skb_trim(skb0, hdrlen + sizeof(m->pvar.msg.eca)); mtp_output(skb0, mtp, NULL); /* send back eca */ } return; } /* * Peform normal buffer updating and retrieval in accordance with Q.704 * (07/96) 5.4.1 and 5.4.3. */ send_coa: link->flags |= SS7_LINK_CHANGEOVER; link->loc_bsnt = 0; skb_queue_purge(&link->rtrvb); skb_queue_purge(&link->cocbb); if ( skb0 || (skb0 = skb_clone(skb, GFP_KERNEL)) ) { m = (ss7mtp_msg *)skb0->nh.raw; m->pvar.mh.si = 0x0; /* snmm */ m->pvar.mh.ni = mtp->ni; m->pvar.mh.mp = 0x3; m->pvar.mh.rl.dpc = link->linkset->adjacent->addr; m->pvar.mh.rl.opc = link->linkset->local->addr; m->pvar.mh.rl.sls = slc; m->pvar.mh.h0 = 0x1; /* chm */ m->pvar.mh.h1 = 0x2; /* coa */ m->pvar.msg.coa.fsnl = 0x0; /* for now */ *(skb0->data) = SS7_L2_PDU; skb0->priority = TC_PRIO_BESTEFFORT; __skb_trim(skb0, hdrlen + sizeof(m->pvar.msg.coa)); link->skb = skb; link->alt = NULL; link->cob_state = SS7_LK_COB_BSNT_REQ_COA; *(skb0->data) = SS7_L2_RETRIEVE_BSNT; skb0->priority = TC_PRIO_CONTROL; __skb_trim(skb, 1); link_output(skb0, link); } } static __inline void changeover_retrieval(struct sk_buff *skb, struct ss7_link* link) { struct sk_buff *skb0 = skb_clone(skb, GFP_ATOMIC); if ( link->rem_bsnt && skb0 ) { link->cob_state = SS7_LK_COB_RETRIEVING; skb0->data[0] = SS7_L2_RETRIEVAL_REQUEST_AND_FSNC; skb0->priority = TC_PRIO_CONTROL; skb0->data[1] = link->rem_bsnt & 0x7f; __skb_trim(skb0, 2); link_output(skb0, link); } else { skb_queue_purge(&link->rtrvb); changeover_divert(link); } } /* 13.5.4 At the reception of a signaling-route-set-test message, a signalling transfer * point will compare the status of the destination in the received message with the * actual status of the destination. If they are the same, no further action is taken. * If they are different, one of the following message is sent in repsonse, dictated by * the actual status of the destination. * * - a transfer-allowed message, referring to the destination the accessibility of which * is tested, if the signalling transfer point can reach the indicated destination via * a signalling link not connected to the signalling point from which the signalling- * route-set-test message was received (and if the transfer restricted procedure is * used in the network, the signalling link is on the normal route or an equally * effecient alternate route); * * - a transfer-restricted message when access to the destination is possible via an * alternative to the normal routing which is less efficient, but still not via the * signalling point from which the signalling-route-set-test was originated. * * - a transfer-prohibited message in all other cases (including inaccessibility of that * destination). */ static void send_rte_status(struct sk_buff *skb, struct ss7mtp_cb *mtp, struct ss7_route *rt) { struct ss7_routeset *rs; struct sk_buff *skb0; struct ss7_route *r; ss7mtp_msg *m; __u8 h1 = 0x1; if ( !(skb0 = skb_clone(skb, GFP_KERNEL)) ) return; rs = rt->routeset; if ( rs-> flags & SS7_RS_PROHIBITED ) { h1 = 0x1; /* tfp */ } else if ( rs-> flags & SS7_RS_RESTRICTED ) { h1 = 0x3; /* tfr */ } else if ( rs-> flags & SS7_RS_ALLOWED ) { h1 = 0x5; /* tfa */ } /* * Spec (Q.704) says that if the only accessible route to the destination * is the source of the routeset test message then we are to sent a TFP * back. */ for ( r= rs-> routes; r; r = r-> rset ) if (( r != rt ) && !( r-> flags & SS7_RT_DONTUSE )) break; if ( !r ) h1 = 0x1; /* tfp */ if ( rs-> type & ( SS7_RST_CLUSTER | SS7_RST_NETWORK ) ) h1++; /* cluster version */ m = (ss7mtp_msg *)skb0->nh.raw; m->pvar.mh.si = 0x0; /* snmm */ m->pvar.mh.ni = mtp->ni; m->pvar.mh.mp = 0x3; m->pvar.mh.rl.dpc = rt->linkset->adjacent->addr; m->pvar.mh.rl.opc = rt->linkset->local->addr; m->pvar.mh.rl.sls = 0x0; m->pvar.mh.h0 = 0x4; /* tfm */ m->pvar.mh.h1 = h1; m->pvar.msg.tfp.dest = rs->addr; *(skb0->data) = SS7_L2_PDU; skb0->priority = TC_PRIO_BESTEFFORT; __skb_trim(skb0, hdrlen + sizeof(m->pvar.msg.tfp)); mtp->output(skb0, mtp, NULL); return; } static void stop_sig_rs_test(struct ss7mtp_cb *mtp, struct ss7_route *rt) { rt->flags &= ~SS7_RT_RSTEST; del_timer(&rt->t); if ( rt->skb ) { kfree_skb( rt->skb ); rt->skb = NULL; } } /* 13.5.2 A signalling-route-set-test message is sent from a signalling point after * transfer-prohibited or transfer-restricted message is received from an adjacent * signalling transfer point (see 13.2.4 and 13.4.4). In this case, a signalling-route- * set-test message is sent to that signalling transfer point referring to the destination * declared inaccessible or restricted by the transfer-prohibited or transfer-restricted * message, every T10 period (see clause 16) until a transfer-allowed message indicating * that the destination has become accessible is received. * * The procedure is used to recover the signalling route availability information that may * not have been received because of some signalling network failure. * * 13.5.3 A signalling-route-set-test message is sent to the adjacent signalling transfer * point as an ordinary signalling network management message. */ static void sig_rte_set_test(struct ss7mtp_cb *mtp, struct ss7_route *rt, __u8 h1) { struct ss7_routeset *rs; struct sk_buff *skb; ss7mtp_msg *m; stop_sig_rs_test(mtp, rt); rt->flags |= SS7_RT_RSTEST; if ( !(skb = mtp_alloc_skb(GFP_KERNEL)) ) return; rs = rt->routeset; if ( rs-> type & ( SS7_RST_NETWORK | SS7_RST_CLUSTER ) ) h1 += 2; m = (ss7mtp_msg *)skb->nh.raw; m->pvar.mh.si = 0x0; /* snmm */ m->pvar.mh.ni = mtp->ni; m->pvar.mh.mp = 0x3; m->pvar.mh.rl.dpc = rt->linkset->adjacent->addr; m->pvar.mh.rl.opc = rt->linkset->local->addr; m->pvar.mh.rl.sls = 0x0; m->pvar.mh.h0 = 0x5; /* rsm */ m->pvar.mh.h1 = h1; /* rsp, rsr, rcp, rcr */ m->pvar.msg.rsp.dest = rs->addr; *(skb->data) = SS7_L2_PDU; skb->priority = TC_PRIO_BESTEFFORT; __skb_trim(skb, hdrlen + sizeof(m->pvar.msg.rsp)); rt->skb = skb; rt-> t.data = (unsigned long)rt; rt-> t.function = &mtp_t10_timeout; rt-> t.expires = jiffies + mtp->t10_value; add_timer(&rt->t); return; } /* 13.9 Signalling-route-set-congestion-test (National Option) * * 13.9.1 The signalling-route-set-congestion-test procedure is used at an originating * signalling point to update the congestion status associated with a route set towards a * certain destination. The purpose is to test whether or not signalling messages * destined towards that destination with a given congestion priority or higher may be * sent. * * In the case of a processor restart the congestion status of all signalling route sets * will be initialized to the zero value. The response mechanism within the transfer- * controlled procedure will correct signalling route sets whose congestion status does * not have the zero value. * * ... * * 13.9.2 The signalling-route-set-congestion-test message differs from other signalling * network management messages in that it is not assigned the highest congestion priority. * Instead, the congestion priority assigned to the signalling-route-set-congestion-test * message to be sent to a given destination is equal to one less that the current * congestion status associated with the signalling route set towards the destination. * * 13.9.3 If within T16 (see clause 16), after sending a signalling-route-set-congestion- * test message, a transfer-controlled message relating to the concerned destination is * received, the signalling point updates the congestion status of the signalling route * set towards the concerned destination with the value of the congestion status carried * in the transfer-controlled message. Following this, the procedure specified in 13.9.4 * and 13.9.5 are performed. * * If T16 (see clause 16) expires after sending a signalling-route-set-congestion-test * message without a transfer-controlled message relating to the concerned destination * having been received, the signalling point changes the congestion status associated * with the signalling route set towards the concerned destination to the next lower * status. * * 13.9.4 Provided that the signalling route set towards destination X is not in the * "unavailable" state, a signalling-route-set-congestion-test message is sent from an * originating signalling point to destination X in the following cases: * * i) When T15 (see clause 16) expires after the last update of the congestion status of * the signalling route set toward destination X by a transfer-controlled message * relating to the same destination. * * ii) When T16 (see clause 16) expires after sending a signalling-route-set-congestion- * test message to destination X without a transfer-controlled message relating to the * same destination having been received. After the congestion status has been * decremented by one, the test is repeated, unless the congestion status is zero. * * 13.9.5 At the reception of a signalling-route-set-congestion-test message, a * signalling transfer point will route it as an ordinary message, i.e. according to the * procedure specified in 2.3.5. * * 13.9.6 When a signalling-route-set-congestion-test message reaches its destination, it * is discarded. */ static void sig_rte_set_cong_test(struct sk_buff *skb, struct ss7mtp_cb *mtp, struct ss7_route *rt) { struct ss7_routeset *rs; struct sk_buff *skb0; ss7mtp_msg *m; rs = rt->routeset; del_timer(&rs->t); if ( rs->skb ) { kfree_skb( rs->skb ); rs->skb = NULL; } rs-> flags |= SS7_RS_CONGESTED; if ( !(skb0 = skb_clone(skb, GFP_KERNEL)) ) { if (rs->skb) goto sig_rte_cong_timer; else return; } m->pvar.mh.si = 0x0; /* snm */ m->pvar.mh.ni = mtp->ni; m->pvar.mh.mp = 0x3; /* initially */ m->pvar.mh.rl.dpc = rs->addr; m->pvar.mh.rl.opc = mtp->saddr.s_addr; m->pvar.mh.rl.sls = 0x0; m->pvar.mh.h0 = 0x3; /* fcm */ m->pvar.mh.h1 = 0x1; /* rct */ *(skb->data) = SS7_L2_PDU; skb->priority = TC_PRIO_BESTEFFORT; __skb_trim(skb, hdrlen + sizeof(m->pvar.msg.rct)); rs->skb = skb0; sig_rte_cong_timer: rs-> cb = mtp; rs-> t.data = (unsigned long)rs; rs-> t.function = &mtp_t15_timeout; rs-> t.expires = jiffies + mtp->t15_value; add_timer(&rs->t); return; } /* * 8.2. Controlled rerouting initiation and actions * * 8.2.1 Controlled rerouting is initiated at a signalling point when a transfer-allowed * message, indicating that the signalling route has become available, is received; also * when a transfer-restricted message is received. * * The following actions are then performed: * * a) transmission of signalling traffic towards the concerned destination on the link * set belonging to the alternative route or the route over which the transfer- * restricted message was received is stopped; such traffic is stored in a "controlled * rerouting buffer"; a timer T6 (see 16.8), is started; * * b) if the signalling point serves as a signalling transfer point, a transfer- * prohibited procedure is performed for the route made available (or the alternate * route in the case of the reception of a transfer-restricted message, if the * alternative route was not previously used), and a transfer-allowed procedure for * the alternative one (or on the restricted route in the case of the reception of a * transfer-restricted message)(see 13.2.2 and 13.3.2, respectively); * * c) at the expiry of T6, the concerned signalling traffic is restarted on an outgoing * link set pertaining to the signalling route made available, or the alternative * route in the case of reception of the transfer-restricted message, starting with * the content of the controlled rerouting buffer; the aim of the time delay is to * minimize the prabability of out-of-sequence deliver to the destination point(s). * * 8.2.2 In the case when there is not signalling traffic to be diverted fromt the route * made available, only action b) in 8.2.1 applies. * * 8.2.3 If the destination was inaccessible or restricted, when the route is made * available, then the destination is declared accessible and actions specified in 6.2.3 * and 6.2.4 apply (if appropriate). */ /* 6.2.3 In the case that the signalling link made available can be used to carry * signalling traffic towards a non-adjacent destination which was previously declared * inaccessible, the following actions apply: * * i) the routing of the concerned signalling traffic is unblocked and transmission of * the concerned messages (if any) is started on the link made available; * * ii) an indication is sent to the User Part(s)(if any) to restart the concerned * signalling traffic; * * iii) the transfer-allowed procedure is performed, as specified in 13.3. However, in * national networks, when the recovered link is not on the normal route for that * destination, the transfer-restricted procedure may be performed as specified in * 13.4. * * iv) the transfer-prohibited procedure is performed as specified in 13.2.2 i). * */ /* * Build a txm ( tfp,tcp,tfr,tcr,tfa,tca ) message in a sk_buff copy with no * dpc. */ static __inline struct sk_buff *build_tfm(struct ss7mtp_cb *mtp, struct ss7_routeset *rs, __u32 daddr, __u8 h1) { struct sk_buff *skb; ss7mtp_msg *m; if ( rs-> type & ( SS7_RST_NETWORK | SS7_RST_CLUSTER ) ) h1++; /* cluster form */ if ( !(skb = mtp_alloc_skb(GFP_KERNEL)) ) return NULL; m = (ss7mtp_msg *)skb-> nh.raw; m-> pvar.mh.si = 0x0; /* stm msg */ m-> pvar.mh.ni = mtp->ni; m-> pvar.mh.mp = 0x3; m-> pvar.mh.rl.dpc = daddr; m-> pvar.mh.rl.opc = mtp->saddr.s_addr; /* from us */ m-> pvar.mh.rl.sls = 0x0; /* send TFA/TFP on fixed SLS */ m-> pvar.mh.h0 = 0x4; /* tfm */ m-> pvar.mh.h1 = h1; /* tfx or tcx */ m-> pvar.msg.tfp.dest = rs->addr; *(skb->data) = SS7_L2_PDU; skb->priority = TC_PRIO_BESTEFFORT; __skb_trim(skb, hdrlen + sizeof(m->pvar.msg.tfa)); return skb; } /* * Broadcast to all adjacent destination point codes except point codes which * are adjacent on a route in the set which matches `flags'. This function * consumes the skb provided. */ static __inline void broadcast(struct sk_buff *skb, struct ss7mtp_cb *mtp, struct ss7_routeset *rs, __u8 flags) { struct ss7_linkset *ls; struct ss7_route *r; struct sk_buff *skb0; ss7mtp_msg *m = (ss7mtp_msg *)skb->nh.raw; for ( ls = ss7_all_linksets ; ls ; ls = ls-> next ) { struct ss7_routeset *ra = ls-> adjacent; if ( ra-> flags & SS7_RS_DONTUSE ) continue; /* dont send to inaccessible adjacent */ for ( r = rs-> routes ; r ; r = r-> next ) if ( r-> linkset == ls && r-> flags & flags ) goto tfa_next_routeset; /* dont send already informed adjacent */ m-> pvar.mh.rl.dpc = ra->addr; /* send to adjacent */ if ( (skb0 = skb_clone(skb, GFP_ATOMIC)) ) mtp_output(skb0, mtp, ra); tfa_next_routeset: } kfree_skb(skb); } static void broadcast_tfa(struct ss7mtp_cb *mtp, struct ss7_routeset *rs) { struct sk_buff *skb; if ( rs-> flags & SS7_RS_PROHIBITED ) mtp_resume(mtp,rs); rs-> flags |= SS7_RS_ALLOWED; rs-> flags &= ~( SS7_RS_PROHIBITED | SS7_RS_RESTRICTED ); if ( (skb = build_tfm(mtp, rs, 0U, 0x5)) ) /* tfa */ broadcast(skb, mtp, rs, SS7_RS_ALLOWED); } static void broadcast_tfr(struct ss7mtp_cb *mtp, struct ss7_routeset *rs) { struct sk_buff *skb; if ( rs-> flags & SS7_RS_PROHIBITED ) mtp_resume(mtp,rs); rs-> flags |= SS7_RS_RESTRICTED; rs-> flags &= ~( SS7_RS_PROHIBITED | SS7_RS_ALLOWED ); if ( (skb = build_tfm(mtp, rs, 0U, 0x3)) ) /* tfr */ broadcast(skb, mtp, rs, ( SS7_RS_ALLOWED | SS7_RS_RESTRICTED )); } static void broadcast_tfp(struct ss7mtp_cb *mtp, struct ss7_routeset *rs) { struct sk_buff *skb; if ( !(rs-> flags & SS7_RS_PROHIBITED) ) mtp_pause(mtp,rs); rs-> flags |= SS7_RS_PROHIBITED; rs-> flags &= ~( SS7_RS_RESTRICTED | SS7_RS_ALLOWED ); if ( (skb = build_tfm(mtp, rs, 0U, 0x1)) ) /* tfp */ broadcast(skb, mtp, rs, SS7_RS_PROHIBITED); } /* * Find an alternate usable route */ static __inline ss7_route *alt_route(struct ss7_route *rt) { struct ss7_routeset *rs = rt->routeset; struct ss7_route *ru; for ( ru = rs-> routes ; ru ; ru = ru-> next ) if ( ( ru != rt ) && !( ru-> flags & SS7_RT_DONTUSE ) ) break; return ( ru ); } /* 6.2.3 In the case that the signalling link made available can be used to carry * signalling traffic towards a non-adjacent destination which was previously declared * inacessible, the following actions apply: * * i) the routing of the concerned signalling traffic is unblocked and transmission of * the concerned messages (if any) is started on the link made available; * * ii) an indication is sent to the User Part(s) (if any) to restart the concerned * signalling traffic; * * iii)the transfer-allowed procedure is performed, as specified in 13.3. However, in * national networks, when the recovered link is not on the normal route for that * destination, the transfer-restricted procedure may be performed as specified in * 13.4; * * iv) the transfer-prohibited procedure is performed as specified in 13.2.2 i). */ static __inline void route_allow(struct ss7mtp_cb *mtp, struct ss7_route *ra) { struct sk_buff *skb; struct ss7_routeset *rs; struct ss7_route *ru; if ( ra-> flags & SS7_RT_ALLOWED ) return; /* already allowed */ ra-> flags |= SS7_RT_ALLOWED; ra-> flags &= ~( SS7_RT_PROHIBITED | SS7_RT_RESTRICTED | SS7_RT_CONGESTED ); rs = ra->routeset; ru = alt_route(ra); /* another usable route? */ if ( ru ) { if ( ru-> priority < ra-> priority ) return; /* won't use ra */ del_timer(&ra->t); ra-> flags |= SS7_RT_CONTROLLEDRR; ra-> t.data = (unsigned long)ra; ra-> t.function = &mtp_t6_timeout; ra-> t.expires = jiffies + mtp->t6_value; add_timer(&ra->t); } if ( ra-> priority > 1 ) /* will use ra as alternate */ if ( (skb = build_tfm(mtp, rs, ra->linkset->adjacent->addr, 0x1)) ) /* tfp */ mtp_output(skb, mtp, ra->linkset->adjacent); if ( ru ) { if ( ru->priority > ra-> priority || ru->flags & SS7_RT_RESTRICTED ) { /* won't use ru alternate */ if ( (skb = build_tfm(mtp, rs, ru->linkset->adjacent->addr, 0x5)) ) /* tfa */ mtp_output(skb, mtp, ru->linkset->adjacent); } else /* will use both load-shared */ return; } /* will only use ra */ if ( ra-> priority > 1 ) broadcast_tfr(mtp,rs); /* new alternate */ else broadcast_tfa(mtp,rs); /* new primary */ } /* * 13.4.2 A transfer-restricted message relating to a given destination X is sent from a * signalling transfer point Y when the normal link set (combined link set) used by * signalling point Y to route to destination X experiences long-term failure such as * equipment failure, or there is congestion on an alternative link set currently being * used to destination X. In this case, a transfer-restricted message is sent to all * accessible adjacent signalling points except those that receive TFP message according * to 13.2.2 i), and except signalling point X if it is an adjacent point (Broadcast * Method). * * When an adjacent signalling point X become acessible, the STP Y sends to X transfer- * restricted messages concerning destinations that are restricted from Y (see clause 9). * * When a signalling point Y restarts, it broadcasts to all accessible adjacent signnlling * points transfer-restricted messages concerning destinations that are restricted from Y * (see clause 9). * * 13.4.3 When a signalling point receives a transfer-restricted message from signalling * transfer point Y and has an alternative equal priority link set available and not * restricted to destination X, it performs actions in 8.2. In other words, it performs * controlled re-routing to maintain the sequence of messages while diverting them to the * alternate link set. If it cannot perform alternate routing to destination X because no * alternative link set is available, it may generate additional transfer-restricted * messages. * * 13.4.4 In some circumstances, it may happen that a signalling point receives either a * repeated transfer-restricted message or a transfer- restricted message relating to a * non-existent route (i.e., there is no route from that signalling point to the concerned * destination via signalling transfer point Y, according to the signalling network * configuration); in this case, no actions are taken. * * 13.4.5 When a transfer-restricted message is received updating a transfer-prohibited * status, signalling traffic management decides if an alternative route is available or * restricted; if it is not (i.e., no alternative route exists), the concerned traffic is * restarted towards the signalling point from which the transfer-restricted message was * received. Otherwise, no other actions are taken. */ static __inline void route_restrict(struct ss7mtp_cb *mtp, struct ss7_route *rr) { struct sk_buff *skb; struct ss7_routeset *rs; struct ss7_route *ru; __u8 oldflags = rr->flags; if ( rr-> flags & SS7_RT_RESTRICTED ) return; /* already restricted */ rr-> flags |= SS7_RT_RESTRICTED; rr-> flags &= ~( SS7_RT_PROHIBITED | SS7_RT_ALLOWED ); rs = rr->routeset; ru = alt_route(rr); /* alternate usable route? */ if ( oldflags & SS7_RT_PROHIBITED ) { /* route was prohibited, now it's restricted */ rr-> flags &= ~( SS7_RT_CONGESTED ); if ( ru ) { if ( ru-> priority < rr-> priority ) return; /* won't use rr */ if ( ru-> priority == rr-> priority && ru->flags & SS7_RT_ALLOWED ) /* won't use rr */ return; del_timer(&rr->t); rr-> flags |= SS7_RT_CONTROLLEDRR; rr-> t.data = (unsigned long)rr; rr-> t.function = &mtp_t6_timeout; rr-> t.expires = jiffies + mtp->t6_value; add_timer(&rr->t); } if ( rr-> priority > 1 ) /* will use rr as alternate */ if ( (skb = build_tfm(mtp, rs, rr->linkset->adjacent->addr, 0x1)) ) /* tfp */ mtp_output(skb, mtp, rr->linkset->adjacent); if ( ru ) { if ( ru->priority > rr-> priority ) { /* won't use ru alternate */ if ( (skb = build_tfm(mtp, rs, ru->linkset->adjacent->addr, 0x5)) ) /* tfa */ mtp_output(skb, mtp, ru->linkset->adjacent); } else /* will use both load-shared */ return; } } else { /* route was allowed, now it's restricted */ if ( ru ) { if ( ru-> priority < rr-> priority ) return; /* wasn't using rr */ if ( ru-> priority > rr-> priority || ru->flags & SS7_RT_RESTRICTED ) return broadcast_tfr(mtp,rs); /* can't reroute */ del_timer(&rr->t); rr-> flags |= SS7_RT_CONTROLLEDRR; rr-> t.data = (unsigned long)rr; rr-> t.function = &mtp_t6_timeout; rr-> t.expires = jiffies + mtp->t6_value; add_timer(&rr->t); return; } } broadcast_tfr(mtp,rs); /* can't reroute */ } /* 7.2 Forced rerouting initiation and actions * * 7.2.1 Forced reouting is initiated at a signalling point when a transfer-prohibited * message indicating a signalling route unavailability is received. * * The following actions are then performed: * * a) transmission of signalling traffic towards the concerned destination on the link * set(s) pertaining to the unavailable route is immediately stopped; such traffic is * stored in a forced rerouting buffer; * * b) the alternative route is determined according to the rules specified in clause 4; * * c) as soon as action b) is completed, the concerned signalling traffic is restarted on * a link set pertaining to the alternative route, starting with the content of the * forced rerouting buffer; * * d) if appropriate, a transfer-prohibited procedure is performed (see 13.2.2). */ /* 5.3.3 If no alternative signalling link exists for signalling traffic towards on or * more destinations, the concerned destination(s) are declared inaccessible and the * following actions apply: * * i) the routing of the concerned signalling traffic is blocked and the concerned * messages already stored in the transmission and retransmission buffers of the * unavailable signalling link, as well as those received subsequently, are discarded; * * ii) a command is sent to the User Part(s) (if any) in order to stop generating the * concerned signalling traffic; * * iii)the transfer-prohibited procedure is performed, as specified in 13.2; * * iv) the appropriate signalling link management procedures are performed, as specified * in clause 12. */ /* 13.2.3 When a signalling point receives a transfer-prohibited message from signalling * transfer point Y, it peforms the actions specified in clause 7 (since reception of * transfer-prohibited message indicates the unavailability fo the concerned signalling * route, see 3.4.1). In other words, it may perform forced re-routing and, if * appropriate, generate additional transfer-prohibited messages. * * 13.2.4 In some circumstances it may happen that a signalling point receives either a * repeated transfer-prohibited message relating to a non-existent route (i.e., there is * no route from that signalling point to the concerned destination via sginalling * transfer point Y, according to the signalling network configuration) or to a * destination which is already inacccessible, due to previous failures, in this case no * actions are taken. */ static __inline void route_prohibit(struct ss7mtp_cb *mtp, struct ss7_route *rp) { struct ss7_routeset *rs; struct ss7_route *ru; __u8 oldflags = rp-> flags; if ( rp-> flags & SS7_RT_PROHIBITED ) return; /* already prohibited */ rp-> flags |= SS7_RT_PROHIBITED; rp-> flags &= ~( SS7_RT_RESTRICTED | SS7_RT_ALLOWED | SS7_RT_CONGESTED ); rs = rp->routeset; ru = alt_route(rp); /* alternate usable route? */ if ( oldflags & SS7_RT_ALLOWED ) { /* route was allowed, now prohibited */ if ( ru ) { if ( ru-> priority < rp-> priority ) return; /* wasn't using rp */ if ( ru-> priority > rp-> priority || ru->flags & SS7_RT_RESTRICTED ) return broadcast_tfr(mtp,rs); /* reroute to restricted route */ } } else { /* route was restricted, now prohibited */ if ( ru ) { if ( ru-> priority < rp-> priority ) return; /* wasn't using rp */ if ( ru-> priority > rp-> priority || ru->flags & SS7_RT_RESTRICTED ) return; /* I was already restricted */ } } broadcast_tfp(mtp,rs); /* can't reroute */ del_timer(&rs->t); rs->t.data = (unsigned long)rs; rs->t.function = &mtp_t8_timeout; rs->t.expires = jiffies + mtp->t8_value; add_timer(&rs->t); return; } /* * Send an SLTM message on the specified link. Set appropriate SLTM timers * on the link. */ static __inline void send_sltm(struct ss7_link *link) { struct ss7mtp_cb *mtp = link->linkset->local->cb; struct sk_buff *skb; ss7mtp_msg *m; del_timer(&link->t1t); del_timer(&link->t2t); if ( (skb = mtp_alloc_skb(GFP_ATOMIC)) ) { m = (ss7mtp_msg *)skb->nh.raw; m->pvar.mh.si = 0x1; /* SNTM */ m->pvar.mh.ni = mtp->ni; m->pvar.mh.mp = 0x3; m->pvar.mh.rl.opc = link->linkset->local->addr; m->pvar.mh.rl.dpc = link->linkset->adjacent->addr; m->pvar.mh.rl.sls = link->index; m->pvar.mh.h0 = 0x1; /* TM */ m->pvar.mh.h1 = 0x1; /* SLTM */ m->pvar.msg.sltm.slc = link->index; m->pvar.msg.sltm.tli = 0x0; /* * FIXME: check to see if TLI=0 is ok here on test messages. */ *(skb->data) = SS7_L2_PDU; skb->priority = TC_PRIO_BESTEFFORT; __skb_trim(skb, hdrlen + sizeof(m->pvar.msg.sltm) - 15); link_output(skb, link); } link->t1t.data = (unsigned long)link; link->t2t.data = (unsigned long)link; link->t1t.function = &mtp_t1t_timeout; link->t2t.function = &mtp_t2t_timeout; link->t1t.expires = jiffies + mtp->t1t_value; link->t2t.expires = jiffies + mtp->t2t_value; add_timer(&link->t1t); add_timer(&link->t2t); } static void link_up(struct ss7_link *link, __u8 reason); /* * Signalling Link Test Control messages. */ static void ss7mtp_sltc_msg(struct sk_buff *skb, struct ss7mtp_cb *mtp, struct ss7_routeset *rt) { ss7mtp_msg *m = (ss7mtp_msg *)skb->nh.raw; struct ss7_link *link; /* link we received message on */ unsigned h0 = m->pvar.mh.h0; unsigned h1 = m->pvar.mh.h1; if (!(link = &((struct ss7_iface *)skb->dev->ss7_ptr)->link)) return; switch (h0) { case 0x1: /* TM */ switch (h1) { case 0x1: /* SLTM */ { struct sk_buff *skb0; int len; if ( (skb0 = skb_clone(skb, GFP_ATOMIC) ) ) { m = (ss7mtp_msg *)skb0->nh.raw; m->pvar.mh.si = 0x1; /* SNTM */ m->pvar.mh.ni = mtp->ni; m->pvar.mh.mp = 0x3; m->pvar.mh.rl.opc = link->linkset->local->addr; m->pvar.mh.rl.dpc = link->linkset->adjacent->addr; m->pvar.mh.rl.sls = link->index; m->pvar.mh.h0 = 0x1; /* TM */ m->pvar.mh.h1 = 0x2; /* SLTA */ m->pvar.msg.slta.slc = link->index; len = m->pvar.msg.slta.tli; *(skb0->data) = SS7_L2_PDU; skb0->priority = TC_PRIO_BESTEFFORT; __skb_trim(skb0, hdrlen + sizeof(m->pvar.msg.slta) - 15 + len); link_output(skb0, link); } return; } case 0x2: /* SLTA */ { /* FIXME: we should actually check * contents of SLTA message... */ del_timer(&link->t1t); if ( link-> flags & SS7_LINK_TEST ) { /* First successful link test, bring * link into service at L3. */ link-> flags &= ~(SS7_LINK_TEST|SS7_LINK_RETEST); link_up(link, SS7_LINK_OUT_OF_SERVICE); return; } link-> flags &= ~(SS7_LINK_TEST|SS7_LINK_RETEST); return; } } } return; } /* * Signalling Link Management Messages. */ static void ss7mtp_slm_msg(struct sk_buff *skb, struct ss7mtp_cb *mtp, struct ss7_routeset *rt) { } /* * Signalling Traffic Management Messages. */ static void ss7mtp_stm_msg(struct sk_buff *skb, struct ss7mtp_cb *mtp, struct ss7_routeset *rt) { ss7mtp_msg *m = (ss7mtp_msg *)skb->nh.raw; struct ss7_link *lr; /* link we received message on */ struct ss7_link *lc; /* concerned link */ unsigned h0 = m->pvar.mh.h0; unsigned h1 = m->pvar.mh.h1; if (!(lr = &((struct ss7_iface *)skb->dev->ss7_ptr)->link)) return; switch (h0) { case 0x7: /* TRM */ switch (h1) { /* STMM */ case 0x1: /* TRA - Traffic restart allowed signal */ /* * This is the end of a MTP restart procedure and we are supposed * to dump our TFP's and TFR's at the restarted signaling point. * A restarting signaling point is one which is adjacent had has * been inaccessible. */ /* STMM */ case 0x2: /* TRW - Traffic restart waiting signal */ /* ANSI */ default: return; } case 0x1: /* CHM */ switch (h1) { /* STMM */ case 0x1: /* COO - changeover order signal */ if ( !(lc = find_link( m->pvar.mh.rl.opc, m->pvar.mh.rl.sls )) ) return; lc->rem_bsnt = m->pvar.msg.coo.fsnl | 0x80; send_changeover_ack(skb,lc); return; /* STMM */ case 0x2: /* COA - changeover acknowledgement signal */ if ( !(lc = find_link( m->pvar.mh.rl.opc, m->pvar.mh.rl.sls )) ) return; if ( !(lc->flags & SS7_LINK_CHANGEOVER) || lc->cob_state != SS7_LK_COB_WAITING_ACK ) return; lc->rem_bsnt = m->pvar.msg.coa.fsnl | 0x80; changeover_retrieval(skb,lc); return; /* STMM */ case 0x3: /* CBD - changeback declaration signal */ if ( !(lc = find_link( m->pvar.mh.rl.opc, m->pvar.mh.rl.sls )) ) return; m->pvar.mh.rl.dpc = lc->linkset->adjacent->addr; m->pvar.mh.rl.opc = lc->linkset->local->addr; m->pvar.mh.h1 = 0x4; /* cba */ mtp_output(skb, mtp, NULL); return; /* STMM */ case 0x4: /* CBA - changeback acknowledgement signal */ if ( !(lc = find_link( m->pvar.mh.rl.opc, m->pvar.mh.rl.sls )) ) return; if ( !(lc->flags & SS7_LINK_CHANGEBACK) || lc->cob_state != SS7_LK_COB_WAITING_ACK ) return; changeback_divert(lc); return; default: return; } case 0x2: /* ECM */ switch (h1) { /* STMM */ case 0x1: /* ECO - emergency changeover order signal */ if ( !(lc = find_link( m->pvar.mh.rl.opc, m->pvar.mh.rl.sls )) ) return; lc->rem_bsnt = 0x00; send_changeover_ack(skb,lc); return; /* STMM */ case 0x2: /* ECA - emergency changeover ack signal */ if ( !(lc = find_link( m->pvar.mh.rl.opc, m->pvar.mh.rl.sls )) ) return; if ( !(lc->flags & SS7_LINK_CHANGEOVER) || lc->cob_state != SS7_LK_COB_WAITING_ACK ) return; lc->rem_bsnt = 0x00; changeover_retrieval(skb,lc); return; default: return; } case 0x6: /* MIM */ switch (h1) { /* STMM */ case 0x1: /* LIN - link inhibit signal */ /* STMM */ case 0x2: /* LUN - link uninhibit signal */ /* STMM */ case 0x3: /* LIA - inhibit acknowledgement signal */ /* STMM */ case 0x4: /* LUA - uninhibited acknowledgement signal */ /* STMM */ case 0x5: /* LID - inhibit denied signal */ /* STMM */ case 0x6: /* LFU - force inhibit signal */ case 0x7: /* LLI - local inhibit test signal */ case 0x8: /* LRI - remote inhibit test signal */ default: return; } } } /* * Signaling Route Management Messages. */ static void ss7mtp_srm_msg(struct sk_buff *skb, struct ss7mtp_cb *mtp, struct ss7_routeset *loc) { struct ss7_route *r = NULL; ss7mtp_msg *m = (ss7mtp_msg *)skb->nh.raw; /* * If TFA, TFR, TFP then dest/opc/dpc -> dest/adjacent/local = route This * is the route for which the message applies. If TCA, TCR, TCP, then * dest is a cluster. we have local already */ struct ss7_addr dest = { m->pvar.msg.tfa.dest }; struct ss7_addr srce = { m->pvar.mh.rl.opc }; struct ss7_routeset *adj = NULL; struct ss7_routeset *rem = NULL; unsigned h0 = m->pvar.mh.h0; unsigned h1 = m->pvar.mh.h1; if ( !(adj = ss7_rt_type(srce, 0, SS7_RST_ADJACENT)) ) return; if ( h0 & 0x1 ) { if ( !(rem = ss7_rt_type(dest, 0, SS7_RST_REMOTE)) ) { rem = ss7_rs_add(dest, 0, SS7_RST_REMOTE); r = ss7_add_route(rem, loc, adj); } } else { if ( !(rem = ss7_rt_type(dest, 0, SS7_RST_CLUSTER)) ) { rem = ss7_rs_add(dest, 0, SS7_RST_CLUSTER); r = ss7_add_route(rem, loc, adj); } } if ( !r ) return; switch ( h0 ) { case 0x4: /* TFM */ { kfree_skb(skb); switch ( h1 ) { case 0x1: /* TFP - transfer prohibited signal */ case 0x2: /* TCP - transfer cluster prohibited signal */ /* ANSI */ route_prohibit(mtp, r); sig_rte_set_test(mtp, r, 0x1); /* rsp */ return; case 0x3: /* TFR - transfer restricted signal */ case 0x4: /* TCR - transfer cluster restricted signal */ /* ANSI */ route_restrict(mtp, r); sig_rte_set_test(mtp, r, 0x2); /* rsr */ return; case 0x5: /* TFA - trasnfer allowed signal */ case 0x6: /* TCA - transfer cluster allowed signal */ /* ANSI */ stop_sig_rs_test(mtp, r); route_allow(mtp, r); return; default: return; } } case 0x3: /* FCM */ { switch ( h1 ) { case 0x1: /* RCT - signaling route set congestion test msg */ return; /* ignore per Q.704 */ /* 13.7.3 When the originating signalling point Z receives a transfer-controlled message * relating to destination X, if the current congestion status of the signalling route set * towards the destination X is less than the congestion status in the transfer-controlled * message, it updates the congestion status of the signalling route set towards * destination X with the value of the congestion status carried in the transfer- * controlled message. * * 13.7.6 In some circumstances it may happen that a signalling point receives a * transfer-controlled message relating to a destination which is already inaccessible to * to previous failures, in this case the transfer- controlled message is ignored. */ case 0x2: /* TFC - transfer controlled signal */ if ( rem->flags & SS7_RS_DONTUSE ) return; if ( m->pvar.msg.tfc.stat > rem-> cong_status ) { rem-> cong_status = m->pvar.msg.tfc.stat; mtp_status(mtp,rem); /* inform users */ sig_rte_set_cong_test(skb, mtp, r); } return; default: return; } } case 0x5: /* RSM */ { switch ( h1 ) { case 0x1: /* RSP - sig route set test prohibited signal */ if ( !( rem-> flags & SS7_RS_PROHIBITED ) ) send_rte_status( skb, mtp, r ); return; case 0x2: /* RSR - sig route set test restricted signal */ if ( !( rem-> flags & SS7_RS_RESTRICTED ) ) send_rte_status( skb, mtp, r ); return; case 0x3: /* RCP - sig route set test cluster prohibited */ /* ANSI */ if ( !( rem-> flags & SS7_RS_PROHIBITED && rem-> type & ( SS7_RST_NETWORK | SS7_RST_CLUSTER ) ) ) send_rte_status( skb, mtp, r ); return; case 0x4: /* RCR - sig route set test cluster restricted */ /* ANSI */ if ( !( rem-> flags & SS7_RS_RESTRICTED && rem-> type & ( SS7_RST_NETWORK | SS7_RST_CLUSTER ) ) ) send_rte_status( skb, mtp, r ); return; default: return; } } case 0x9: /* UFC */ { switch ( h1 ) { case 0x1: /* UPU */ case 0x2: /* UPA */ /* ANSI */ case 0x3: /* UPT */ /* ANSI */ default: return; } } default: return; } return; } /* * Signalling Special Test Control Messages. */ static void ss7mtp_ssltc_msg(struct sk_buff *skb, struct ss7mtp_cb *mtp, struct ss7_routeset *rt) { } /* * Message Transfer Function. * * We have an message which is not destined to an internal route and likely * corresponds to an address off of the platform. We never transfer messages * for MTP parts which do not have the transfer function specified by routing * or socket, plus we never transfer for MTPs which are restarting, to MTPs * which are restarting, or to MTPs which are congested beyond the priority * of the message. Consumes the buffer provided. * */ static __inline void mtp_transfer(struct sk_buff *skb, struct ss7mtp_cb *mtp, struct ss7_routeset *rt) { ss7mtp_msg *m = (ss7mtp_msg *)skb->nh.raw; struct ss7_addr dest = { m->pvar.mh.rl.dpc }; struct ss7_addr adjc; unsigned mp = m->pvar.mh.mp; unsigned sls = m->pvar.mh.rl.sls; struct ss7_route *route; struct ss7_link *link; /* Do not transfer messages if we don't have the transfer function * or are in MTP restart per Q.704 (07/96) 9.6.6. */ if ( mtp->restart || !mtp->transfer) goto mtp_transfer_discard; if ( !(rt) && !(rt = ss7_rt(dest)) ) goto mtp_transfer_discard; if ( rt-> type & SS7_RST_LOCAL ) goto mtp_transfer_discard; if ( rt-> type & SS7_RST_INTERNAL ) { mtp_output(skb, mtp, rt); return; } /* iii) When a message destined to signalling point X is received at signalling transfer * point Y and Y is unable[7] to transfer the message, and if no corresponding timer * T8 is running. In this case the transfer-prohibited message is sent to the * adjacent signaling point from which the message concerned was received (Response * Method). In addition, timer T8 is started concerning SP X. * * Within T8 (see clause 16) after the last transfer-prohibited message was transmitted * according to ii) or iii) above no transfer prohibited message will be sent via the * Response Method referring to that destination. * ---------- * [7] ``unable'' normally means that X is inaccessible or that Y has no routing data for * X. It might be of advantage in national networks (at the discretion of the network * operator) not to send TFP if no routing data for X exists at Y. This would avoid * signalling route set tests for non- existent destinations, which otherwise might * destabilize the network. */ if ( rt->flags & SS7_RS_DONTUSE ) { __u32 mask = SS7_RS_MASK_MEMBER; unsigned h1 = 0x1; if ( rt-> flags & SS7_RS_TFPWAIT ) goto mtp_transfer_discard; if ( rt-> type & SS7_RST_NETWORK ) { mask = SS7_RS_MASK_NETWORK; h1 = 0x2; } if ( rt-> type & SS7_RST_CLUSTER ) { mask = SS7_RS_MASK_CLUSTER; h1 = 0x2; } if ( !(adjc.s_addr = ss7_get_adjacent(skb)) ) goto mtp_transfer_discard; m->pvar.mh.si = 0x0; /* stmm */ m->pvar.mh.mp = 0x3; m->pvar.mh.ni = mtp->ni; m->pvar.mh.rl.dpc = adjc.s_addr; /* to adjacent */ m->pvar.mh.rl.opc = mtp->saddr.s_addr; /* from us */ m->pvar.mh.rl.sls = 0x0; m->pvar.mh.h0 = 0x4; /* tfm */ m->pvar.mh.h1 = h1; /* tfp or tcp */ m->pvar.msg.tfp.dest = rt->addr & mask; *(skb->data) = SS7_L2_PDU; skb->priority = TC_PRIO_BESTEFFORT; __skb_trim(skb, hdrlen + sizeof(m->pvar.msg.tfp)); rt-> flags |= SS7_RS_TFPWAIT; /* we won't send another soon */ del_timer(&rt->t); rt-> t.data = (unsigned long)rt; rt-> t.function = &mtp_t8_timeout; rt-> t.expires = jiffies + mtp->t8_value; add_timer(&rt->t); mtp_output(skb, mtp, NULL); /* this one's from us */ return; } route = ss7_select_rt( rt ); if ( route-> flags & SS7_RT_CONTROLLEDRR ) { skb_queue_tail( &route->ccrb, skb ); return; } link = ss7_select_link(route, sls); if ( link-> flags & ( SS7_LINK_CHANGEOVER | SS7_LINK_CHANGEBACK ) ) { skb_queue_tail( &link->cocbb, skb ); return; } /* * Send repsonse method TFC to originator of mess discarded under * congestion as per Q.704 (07/96) 13.7.2. */ if ( link-> flags & SS7_LINK_CONGESTED && mp < link->cong_status ) { m->pvar.mh.si = 0x0; /* stmm */ m->pvar.mh.mp = 0x3; m->pvar.mh.ni = mtp->ni; m->pvar.mh.rl.dpc = m->pvar.mh.rl.opc; /* to originator */ m->pvar.mh.rl.opc = mtp->saddr.s_addr; /* from us */ m->pvar.mh.rl.sls = 0x0; m->pvar.mh.h0 = 0x3; /* fcm */ m->pvar.mh.h1 = 0x2; /* tfc */ m->pvar.msg.tfp.dest = rt->addr; m->pvar.msg.tfc.stat = link->cong_status; *(skb->data) = SS7_L2_PDU; skb->priority = TC_PRIO_BESTEFFORT; __skb_trim(skb, hdrlen + sizeof(m->pvar.msg.tfc)); mtp_output(skb, mtp, NULL); /* this one's from us */ return; } link_output(skb,link); return; mtp_transfer_discard: kfree_skb(skb); return; } /* * User Part Message. * * Find a socket bound to the User Part or turn around a User Part * Unavailable message back to sender if no bound socket. * */ static __inline void ss7mtp_up_msg(struct sk_buff *skb, struct ss7mtp_cb *mtp, struct ss7_routeset *rt) { /* let's see if there is a socket bound for the user part */ ss7mtp_msg *m = (ss7mtp_msg *)skb->nh.raw; struct sock *sk; struct ss7mtp_cb *local; /* check address bound socket */ local = rt->cb; if (local && (sk = local->sks[m->pvar.mh.si])) { sk->backlog_rcv(sk, skb); /* deliver to socket */ return; } /* check bound any socket */ local = ss7mtp_all; if (local && (sk = local->sks[m->pvar.mh.si])) { sk->backlog_rcv(sk, skb); /* deliver to socket */ return; } /* no bound socket build UPU */ m->pvar.mh.mp = 0x3; m->pvar.mh.rl.dpc = m->pvar.mh.rl.opc; /* to originator */ m->pvar.mh.rl.opc = mtp->saddr.s_addr; m->pvar.mh.h0 = 0x1; /* ufc */ m->pvar.mh.h1 = 0xa; /* upu */ m->pvar.msg.upu.upi = m->pvar.mh.si; m->pvar.msg.upu.dest = rt->addr; m->pvar.mh.si = 0x0; /* snmm */ *(skb->data) = SS7_L2_PDU; /* put a name on it */ skb->priority = TC_PRIO_BESTEFFORT; __skb_trim(skb, hdrlen + sizeof(m->pvar.msg.upu)); mtp_output(skb, mtp, NULL); /* route it and deliver it */ } /* * Input Method for protocol control blocks. * * MTP Protocol Control blocks wishing to receive messages bind this method * to their control block operations. * */ void mtp_input(struct ss7mtp_cb *mtp, struct sk_buff *skb) { /* here's the message with the L2 header pulled */ /* first find out who it's for */ ss7mtp_msg *m = (ss7mtp_msg *)skb->data; struct ss7_routeset *rt = NULL; struct ss7_addr dest; /* find the control block for the linkset the message came in on */ skb->nh.raw = skb->data; dest.s_addr = m->pvar.mh.rl.dpc; if ( !(rt = ss7_rt_type(dest, 0, SS7_RST_LOCAL)) || (rt-> cb != mtp) ) return mtp_transfer(skb, mtp, rt); else { /* we have a local route to the destination, i.e., the message is for * the address on this side of the link that it came in on */ int h0, h1, si; si = m->pvar.mh.si; h0 = m->pvar.mh.h0; h1 = m->pvar.mh.h1; /* * These below can be distributed during MTP restart per rule Q.704 * (07/96) 9.6.7. */ switch (si) { case SS7_PROTO_SNMM: /* 0x0 */ switch (h0) { case 0x7: /* TRM */ switch (h1) { default: goto bad_message; /****/ /* STMM */ case 0x1: /* TRA - Traffic restart allowed signal */ /****/ /* STMM */ case 0x2: /* TRW - Traffic restart waiting signal */ /* ANSI */ } return ss7mtp_stm_msg(skb, mtp, rt); case 0x4: /* TFM */ switch (h1) { /****/ /* SRMM */ default: goto bad_message; /****/ /* SRMM */ case 0x1: /* TFP - transfer prohibited signal */ /****/ /* SRMM */ case 0x2: /* TCP - transfer cluster prohibited signal */ /* ANSI */ /****/ /* SRMM */ case 0x3: /* TFR - transfer restricted signal */ /****/ /* SRMM */ case 0x4: /* TCR - transfer cluster restricted signal */ /* ANSI */ /****/ /* SRMM */ case 0x5: /* TFA - trasnfer allowed signal */ /****/ /* SRMM */ case 0x6: /* TCA - transfer cluster allowed signal */ /* ANSI */ } return ss7mtp_srm_msg(skb, mtp, rt); } /* * Messages received with service indicator = 0001 are handled * normally during the restart procedure - Q.704 (07/96) 9.6.6. */ case SS7_PROTO_SNTM: /* 0x1 */ switch (h0) { case 0x1: /* TM */ switch (h1) { /****/ /* SLTCM */ case 0x1: /* SLTM */ /****/ /* SLTCM */ case 0x2: /* SLTA */ default: goto bad_message; } return ss7mtp_sltc_msg(skb, mtp, rt); default: goto bad_message; } } /* * These below don't distribute during an MTP restart per rule Q.704 * (07/96) 9.6.7. */ if (mtp->restart) goto dont_distribute; switch (si) { case SS7_PROTO_SNMM: /* 0x0 */ switch (h0) { default: goto bad_message; case 0x8: /* DLM */ switch (h1) { default: goto bad_message; /* SLMM */ case 0x1: /* DLC - Sig-data-link-connection-order signal */ /* SLMM */ case 0x2: /* CSS - Connection-sucessful signal */ /* SLMM */ case 0x3: /* CNS - Connection-not-successful signal */ /* SLMM */ case 0x4: /* CNP - Connection-not-possible signal */ } return ss7mtp_slm_msg(skb, mtp, rt); case 0x1: /* CHM */ switch (h1) { default: goto bad_message; /* STMM */ case 0x1: /* COO - changeover order signal */ /* STMM */ case 0x2: /* COA - changeover acknowledgement signal */ /* STMM */ case 0x3: /* CBD - changeback declaration signal */ /* STMM */ case 0x4: /* CBA - changeback acknowledgement signal */ } case 0x2: /* ECM */ switch (h1) { default: goto bad_message; /* STMM */ case 0x1: /* ECO - emergency changeover order signal */ /* STMM */ case 0x2: /* ECA - emergency changeover ack signal */ } case 0x6: /* MIM */ switch (h1) { default: goto bad_message; /* STMM */ case 0x1: /* LIN - link inhibit signal */ /* STMM */ case 0x2: /* LUN - link uninhibit signal */ /* STMM */ case 0x3: /* LIA - inhibit acknowledgement signal */ /* STMM */ case 0x4: /* LUA - uninhibited acknowledgement signal */ /* STMM */ case 0x5: /* LID - inhibit denied signal */ /* STMM */ case 0x6: /* LFU - force inhibit signal */ case 0x7: /* LLI - local inhibit test signal */ case 0x8: /* LRI - remote inhibit test signal */ } return ss7mtp_stm_msg(skb, mtp, rt); case 0x3: /* FCM */ switch (h1) { default: goto bad_message; /* SRMM */ case 0x1: /* RCT - signaling route set congestion test msg */ /* SRMM */ case 0x2: /* TFC - transfer controlled signal */ } case 0x5: /* RSM */ switch (h1) { default: goto bad_message; /* SRMM */ case 0x1: /* RSP - sig route set test prohibited signal */ /* SRMM */ case 0x2: /* RSR - sig route set test restricted signal */ /* SRMM */ case 0x3: /* RCP - sig route set test cluster prohibited */ /* ANSI */ /* SRMM */ case 0x4: /* RCR - sig route set test cluster restricted */ /* ANSI */ } case 0x9: /* UFC */ switch (h1) { /* SRMM */ default: goto bad_message; /* SRMM */ case 0x1: /* UPU */ /* SRMM */ case 0x2: /* UPA */ /* ANSI */ /* SRMM */ case 0x3: /* UPT */ /* ANSI */ } return ss7mtp_srm_msg(skb, mtp, rt); } case SS7_PROTO_SNSM: /* 0x2 */ switch (h0) { default: goto bad_message; case 0x1: /* TM */ switch (h1) { default: goto bad_message; /* SLTCM */ case 0x1: /* SSLTM */ /* ANSI */ /* SLTCM */ case 0x2: /* SSLTA */ /* ANSI */ } return ss7mtp_ssltc_msg(skb, mtp, rt); } /* * For the following, look for a bound socket. If we have a bound * socket which permits the destination address (wildcard 0.0.0 * address permitted) for the specified user part (wildcard 0 port * permitted), then we will transfer the message to that socket. We * stop with the first socket on the list. SCCP is a little * different, because it might be implemented in the kernel... */ case SS7_PROTO_SCCP: /* 0x3 */ #if 0 /* for later when we do SCCP */ if (mtp->sccp) { skb_push(skb, 1); skb->data[0]=SS7_SCCP_PDU; ss7sccp_msg(skb, mtp, rt); /* FIXME: call SCCP control block */ return; } /* otherwise deliver like normal user part */ #endif case SS7_PROTO_TUP: /* 0x4 */ case SS7_PROTO_ISUP: /* 0x5 */ case SS7_PROTO_DUP1: /* 0x6 */ case SS7_PROTO_DUP2: /* 0x7 */ case SS7_PROTO_MTUP: /* 0x8 */ case SS7_PROTO_TUPE: /* 0xC */ case SS7_PROTO_TUPP: /* 0xF */ /* note: we DON'T pull the MTP header, we push the PDU cmd and * the PDU type */ skb_push(skb, 1); *(skb->data) = SS7_L4_PDU; ss7mtp_up_msg(skb, mtp, rt); return; default: if (net_ratelimit()) printk(KERN_WARNING "SS7/MTP: received unknown MTP user-part message on link %s\n", skb->dev->name); } } bad_message: /* report bad message */ dont_distribute: kfree_skb(skb); return; } static __inline ss7_link *alt_link(struct ss7_link *link) { struct ss7_linkset *ls = link->linkset; struct ss7_route *r = ls->adjacent->routes; struct ss7_linkset *s = r->linkset; struct ss7_link *l = NULL; int i; for ( ; r && !l ; r = r->next, s = r->linkset ) if ( s != ls || s->usable > 1 ) for ( i = 0 ; i < 16 ; i++ ) if ( ( ( l = s->links[i] ) && ( l != link ) && !( l->flags & SS7_LINK_DONTUSE ) ) || ( l = NULL ) ) break; return (l); } /* * 5.3 Changeover initiation and actions * * 5.3.1 Changeover is initiated at a signalling point when a signalling link is * recognized as unavailable according to the criteria listed in 3.2.2. * * The following actions are then performed: * * a) transmission and acceptance of message signal units on the concerned signalling link * is terminated; * * b) transmission of link status signal units or fill in signal units, as described in * 5.3/Q.703 takes place; * * c) the alternative signalling link(s) are determined according to the rules specified in * clause 4; * * d) a procedure to update the content of the retransmission buffer of the unavailable * signalling link is performed as specified in 5.4 below; * * e) signalling traffic is diverted to the alternative signalling link(s) as specified in * 5.5 below. * * In addition, if traffic towards a given destination is diverted to an alternative * signalling link terminating in a signalling tranfser point not currently used to carry * traffic towards that destination, a transfer-prohibited procedure is performed as * specified in 13.2. * * 5.3.2 In the case when there is no traffic to transfer from the unavailable signalling * link action, only item b) of 5.3.1 is required. * * 5.3.3 If no alternative signalling link exists for signalling traffic towards one or * more destinations, the concerned destination(s) are declared inaccessible and the * following actions apply: * * i) the routing of concerned signalling traffic is blocked and the concerned messages * already stored in the transmission and retransmission buffers of the unavailable * signalling link, as well as those received subsequently, are discarded[3]; * --------- * [3] The adequacy of this procedure to meet the acceptable dependability objective * in terms of loss of messages requires further study. * * ii) a command is sent to the User Part(s) (if any) in order to stop generating the * concerned signalling traffic; * * iii) the transfer-prohibited procedure is performed, as specified in 13.2; * * iv) the appropriate signalling link mangement procedures are performed, as specified * in clause 12. * * 5.3.4 In some cases of failiure or in some network configurations, the normal buffer * updating and retrieval procedures described in 5.4 and 5.5 cannot be accomplished. In * such cases, the emergency changeover procedures described in 5.6 apply. * * Other procedures to cover possible abnormal cases appear in 5.7. * * 5.4 Buffer updating procedure * * 5.4.1 When a decision to changeover is made, a changeover order is sent to the remote * signalling point. In the case that the changeover was initiated by the reception of a * changeover order (see 5.2), a changeover acknowledgement is sent instead. * * A changeover order is always acknowledged by a changeover acknowledgement, even when * changeover has alread been initiated in accordance with another criterion. * * No priority is given to the changeover order or changeover acknowledgement in relation to * the normal traffic of the signalling link on which messages is sent. * * 5.4.2 The changeover order and changeover acknowledgement are signalling network * management messages and contain the following information: * * - the label, indicating the destination and originating signalling points and the * identity of the unavailable signalling link; * * - the changeover-order (or changeover-acknowledgement) signal; and * * - the forward sequence number fo the last message signal unit accepted from the * unavailable signalling link. * * Formats and codes of the changeover order and the changeover acknowledgement appear in * clause 15. * * 5.4.3 Upon reception of a changeover order or changeover acknowledgement, the * retransmission buffer of the unavailable signalling link is updated (except as noted in * 5.6), according to the information contained in the message. The message signaling units * successive to that indicated by the message are those which have to be retransmitted on * the alternative signalling link(s), according to the retrieval and diversion procedure. * * 5.5 Retrieval and diversion of trafic * * When the procedure to update the retransmission buffer content is completed, the * following actions are performed: * * - the routing of the signalling traffic to be diverted is changed; * * - the signal traffic already stored in the transmission buffers and retransmission * buffer of the unavailable signalling link is sent directly towards the new signalling * link(s), according to the modified routing. * * The diverted signalling traffic will be sent towards the new signalling link(s) in such a * way that the correct message sequence is maintained. The diverted traffic has no * priority in relation to normal traffic already conveyed on the signalling link(s). * * 5.6 Emergency changeover procedures * * 5.6.1 Due to the failure in a signalling terminal, it may be impossible for the * corresponding end of the faulty signalling link to determine the forward sequence number * of the last message signal unit accepted over the unavailable link. In this case, the * concerned end accomplishes, if possible, the buffer updating procedures described in 5.4 * but it makes use of an emergency changeover order or and emergency changeover * acknowledgement instead of the corresponding normal message; these emergency messaages, * the format of which appears in clause 15, do not contain the forward sequence number of * the last accepted message signal unit. Furthermore, the siginalling link is taken out of * service, i.e. the concerned end initiates, if possible, the sending of out-of-service * link status signal units on the unavailable link (see 5.3/Q.703). * * When the other end of the unavailable signalling link receives the emergency changeover * order or acknowledgement, it accommplishes the changeover procedures described in 5.4 and * 5.5, the only difference being that it does not perform either buffer updating or * retrieval. Instead, it directly starts sending the signalling traffic not yet * transmitted on the unavailable link on the alternative signalling link(s). * * The use of normal or emergency messages depends on the local conditions of the sending * signalling point only, in particular: * * - an emergency changeover order is acknowledged by a changeover acknowledgement if the * local conditions are normal; and * * - a changeover order is acknowledged by an emergency changeover acknowledgement if * there are local fault conditions. * * 5.6.2 Time-controlled changeover is initiated when the exchange of changeover messages * is not possible or not desirable, i.e. if any (or several) of the following cases apply: * * i) No signalling pat exists between the two ends of the unavailable link, so that * the exchange of changeover messages is impossible. * * ii) Processor outage indication is received on a link. In this case, if the remote * processor outage condition is only transitory, sending of a changeover order * could result in failure of the link. * * iii) A signalling link currently carrying traffic has been marked (locally or * remotely) inhibited. In this case, time controlled changeover is used to divert * traffic for the inhibited link without causing the link to fail. * * When the concerned signalling point decides to initiate changeover in such circumstances, * after the expirty of time T1 (see 16.8), it starts signalling traffic not yet transmitted * on the unavailable signalling link on the alternative link(s), the purpose of * withholding traffic for time T1 (see 16.8) is to reduce the probability of message * mis-sequencing. * * An example of such a case appears in Annex A/Q.705. * * In the abnormal case when the concerned signalling point is not aware of the situation, * it will start the normal changeover procedure and send a changeover order; in this case * it will receive no changeover message in response and th procedure will be completed as * indicated in 5.7.2. Possible reception of a transfer-prohibited message (sent by an * involved signalling transfer point on reception of the changeover order, see 13.2) will * not affect changeover procedures. * * If time-controlled changeover has been initiated according to case ii) above and if a * changeover order is receoved from the remote and during time T1, it is advantageous to * switch to the normal changeover procedure including retrieval because unnecessary message * loss or sending of old messages is avoided in a simple way. The ability to perform this * switch is considered to be implementation dependent. A changeover acknowledgement * however, must be returned in any case in order to assure the normal completion of the * changeover procedure at the remote end. If a changeover order is received after timer T1 * has expried time-controlled changeover is completed (if not yet done) and an emergency * changeover acknowledgement is sent to the remote end. * * In the case that processor outage is of long-term, the remote side completes the * time-controlled changeover procedure. In order to avoid sending out old messages (see * clause 8/Q.703) the level 2 buffers on both sides of the link should be flushed * immediately, when the local/remote processor outage state terminates. How the flushing * is performed is implementation dependent. The decision whether processor outage is of * long-term is a local thing. At the remote side long-term processor outage occurs when * the time-controlled changeover timer T1 expires. At the local side an equivalent timer * is used in quite the same way. * * 5.6.3 Due to failures, it may be impossible for signalling point to perform retrieval * even if it has received the retrieval information from the far end of the unavailable * singalling link. In this case, it starts sending new traffic on reception of the * changeover message (or on time-out expiry, see 5.6.2 and 5.7.2); no further action in * addition to the other normal changeover procedures are performed. * * 5.7 Procedures in abnormal conditions * * 5.7.1 The procedures described in this subclause allow the completion of the changeover * procedures in abnormal cases other than those described in 5.6. * * 5.7.2 If no changeover message in response to a changeover order is received within a * timer T2 (see 16.8), new traffic is started on the alternative signalling link(s). * * 5.7.3 If a changeover order or acknowledgement containing an unreasonable value of the * forward sequence number is received, no buffer updating or retrieval is performed, and * new traffic is started on the alternative signalling link(s). * * 5.7.4 If a changeover acknowledgement is received without having previously sent a * changeover order, no action is taken. * * 5.7.5 If a changeover order is received relating to a particular singalling link after * the completion of changeover from that signalling link, an emergency changeover * acknowledgement is sent in response, without any further action. */ static __inline void changeback_abort(struct ss7_link *link); static void link_down(struct ss7_link *link, __u8 reason) { if ( link->flags & SS7_LINK_DONTUSE ) { link->flags |= reason; return; } if ( link->flags & SS7_LINK_CHANGEBACK ) { changeback_abort(link); } link->flags |= SS7_LINK_CHANGEOVER; link->flags |= reason; /* tell link to send FISU/SIOS per Q.704 (07/96) 5.3.1(b) */ /* * If there was no traffic on the signalling link gone unavailable, * perform the changeover diversion procedure immediately (as per Q.704 * (07/96) 5.3.2. */ { struct ss7_route *r; for ( r = link->linkset-> routes ; r ; r = r-> lset ) if ( !( r-> flags & SS7_RT_DONTUSE ) ) break; if (!r) return changeover_divert(link); } { struct ss7_link *alt; if ( (alt = alt_link(link)) ) { struct ss7mtp_cb *mtp = link->linkset->local->cb; struct sk_buff *skb0, *skb = mtp_alloc_skb(GFP_KERNEL); ss7mtp_msg *m = (ss7mtp_msg *)skb->nh.raw; struct ss7_addr adjc = { link->linkset->adjacent->addr }; link->skb = skb; /* * If we can't communicate with the adjacent node (no buffers, no * route) perform the time-controlled procedure. Per Q.704 * (07/96) 5.6.2 and 5.6.2 i). */ if ( !skb || !ss7_rt(adjc) ) { link->cob_state = SS7_LK_COB_TIME_CONTROLLED; del_timer(&link->t); link->t.data = (unsigned long)link; link->t.function = &mtp_t1_timeout; link->t.expires = jiffies + mtp->t1_value; add_timer(&link->t); return; } /* * If we have a route to the adjacent signalling point, it might * go away before we get around to sending the COO/ECO. That's * acceptable per Q.704 (07/96) 5.6.2 ``abnormal case''. */ else { } /* * Prepare a message for COO or COA to be used after buffer * updating in the procedures per Q.704 (07/96) 5.4.1. */ m->pvar.mh.si = 0x0; /* snmm */ m->pvar.mh.ni = mtp->ni; m->pvar.mh.mp = 0x3; m->pvar.mh.rl.dpc = link->linkset->adjacent->addr; m->pvar.mh.rl.opc = link->linkset->local->addr; m->pvar.mh.rl.sls = 0x0; /* can be same sls as failed link */ m->pvar.mh.h0 = 0x1; /* chm */ /* 0x2 for ecm */ m->pvar.mh.h1 = 0x1; /* coo */ /* 0x1 for eco */ *(skb->data) = SS7_L2_PDU; skb->priority = TC_PRIO_BESTEFFORT; __skb_trim(skb, hdrlen + sizeof(m->pvar.msg.coo)); /* * If we can't get a buffer to ask for BSNT, do an ECO per Q.704 * (07/96) 5.3.4. */ if ( !(skb0 = skb_clone(skb, GFP_KERNEL)) ) { /* can't ask for BSNT, do ECO */ m->pvar.mh.h0 = 0x2; /* ecm */ link_output(skb, alt); link->cob_state = SS7_LK_COB_WAITING_ACK; del_timer(&link->t); link->t.data = (unsigned long)link; link->t.function = &mtp_t2_timeout; link->t.expires = jiffies + mtp->t2_value; add_timer(&link->t); return; } /* * Perform the buffer updating procedure per Q.704 (07/96) 5.4. */ link->skb = skb; link->alt = alt; skb0->data[0] = SS7_L2_RETRIEVE_BSNT; skb0->priority = TC_PRIO_CONTROL; __skb_trim(skb, 1); link_output(skb, link); return; /* wait for SS7_L3_BSNT (buffer update) */ } } /* * No alternative signalling link exists for traffic on the failed * signalling link. Perform procedure per Q.704 (07/96) 5.3.3. */ skb_queue_purge(&link->cocbb); skb_queue_purge(&link->rtrvb); changeover_divert(link); /* 5.3.3 ... * * iv) the appropriate signalling link management procedures are performed, as specified * in clause 12. */ /* * 12.2.2 Signalling link restoration * * After a signialling link failure is detected, signialling link initial * alignment will take place. In the case wehn the initial alignment * procedure is successful, a signalling link test is started. If the * signalling link test is successful the link becomes restored and thus * available for signalling. * * If initial alignment is not possible, as determined at Message Transfer * Part level 2 (see clause 7/Q.703, new initial alignment procedures may be * started on the same signalling link after a timer T17 until the signalling * link is restored or a manual intervention is made, e.g. to replace the * signalling data link or the signalling terminal. * * If the signalling link set test fails, the restoration procedure is * repeated until the link is restored or a manual intervention made. */ /* FIXME: do some procedures from clause 12. */ return; } /* * Perform diversion of signal traffic from a failed link according to * changeover procedures in Q.704 (07/96) 5.3.1, 5.3.3, and 5.5, and (if * necessary) clause 6. */ static __inline void changeover_divert(struct ss7_link *link) { struct ss7mtp_cb *mtp; struct sk_buff *skb0 = NULL; struct ss7_routeset *adj; struct ss7_route *r; int i, len; link->cob_state = SS7_LK_COB_IDLE; /* * If the link recovered during changeover, perform the procedures * indicated per Q.704 (07/96) Figure 30/Q.704 (sheet 5 of 6). */ if ( link->flags & SS7_LINK_CHANGEBACK ) return link_up(link, link->reason); del_timer(&link->t); link->flags &= ~(SS7_LINK_CHANGEOVER); link->alt = NULL; link->loc_bsnt = 0x00; link->rem_bsnt = 0x00; if (link->skb) { kfree_skb(link->skb); link->skb = NULL; } mtp = link->linkset->local->cb; adj = link->linkset->adjacent; /* * If required, perform the procedures associated with route * unavailability per Q.704 (07/96) 5.3.3. */ if ( !(link->linkset->usable--) ) for ( r = link->linkset-> routes ; r ; r = r-> lset ) route_prohibit(mtp, r); if ( (skb0 = mtp_alloc_skb(GFP_KERNEL)) ) { *(skb0->data) = SS7_L2_CLEAR_BUFFERS; skb0->priority = TC_PRIO_CONTROL; __skb_trim(skb0, 1); link_output(skb0, link); } /* * Perform diversion procedures per Q.704 (07/96) 5.5. */ while ( (skb0 = skb_dequeue(&link->rtrvb)) ) { mtp_output(skb0, mtp, adj); } for ( i = 0, len = skb_queue_len(&link->cocbb) ; i < len ; i++ ) if ( (skb0 = skb_dequeue(&link->cocbb)) ) { mtp_output(skb0, mtp, adj); /* may requeue */ } } /* * Abort changeover on a link following procedures indicated in Q.704 (07/96) * Figure 30/Q.704 (sheet 3 of 6). */ static __inline void changeover_abort(struct ss7_link *link) { struct sk_buff *skb0 = NULL; del_timer(&link->t); link->flags &= ~(SS7_LINK_CHANGEOVER); link->alt = NULL; link->loc_bsnt = 0x00; link->rem_bsnt = 0x00; link->cob_state = SS7_LK_COB_IDLE; if (link->skb) { kfree_skb(link->skb); link->skb = NULL; } while ( (skb0 = skb_dequeue(&link->rtrvb)) ) link_output(skb0, link); while ( (skb0 = skb_dequeue(&link->cocbb)) ) link_output(skb0, link); } static __inline void changeback_divert(struct ss7_link *link) { struct ss7mtp_cb *mtp; struct sk_buff *skb0 = NULL; struct ss7_routeset *adj; struct ss7_route *r; int i, len; del_timer(&link->t); link->flags &= ~(SS7_LINK_CHANGEBACK); link->cob_state = SS7_LK_COB_IDLE; if (link->skb) { kfree_skb(link->skb); link->skb = NULL; } mtp = link->linkset->local->cb; adj = link->linkset->adjacent; if ( (link->linkset->usable++) == 1 ) for ( r = link->linkset-> routes ; r ; r = r-> lset ) route_allow(mtp, r); for ( i = 0, len = skb_queue_len(&link->cocbb) ; i < len ; i++ ) if ( (skb0 = skb_dequeue(&link->cocbb)) ) { mtp_output(skb0, mtp, adj); /* may requeue */ } if ( link->flags & SS7_LINK_CHANGEOVER ) return link_down(link, link->reason); } /* * Cancel a changeback as a result of link failure during changeback. * Anything buffered in the changeback buffer (cocbb) now becomes the * changeover buffer (cocbb). */ static __inline void changeback_abort(struct ss7_link *link) { del_timer(&link->t); link->flags &= ~(SS7_LINK_CHANGEBACK); link->cob_state = SS7_LK_COB_IDLE; if (link->skb) { kfree_skb(link->skb); link->skb = NULL; } } /* 6.2 Changeback initiation and actions * * 6.2.1 Changeback is initiated at a signalling point when a signalling link is restored, * unblocked or unihibited, and therefore it becomes once again available, according to the * criteria listed in 3.2.3 and 3.2.7. The following actions are then performed: * * a) the alternative signalling link(s) to which traffic normally carried by the * signalling link made available was previously diverted (e.g. on occurrence of a * changeover), are determined. To this set are added, if applicable, other links * determined as defined in 4.4.2; * * b) signalling traffic is diverted (if appropriate, according to the criteria specified * in clause 4) to the concerned signalling link by means of the sequence control * procedure specified in 6.3; traffic diversion can be performed at the discretion of * the signalling point initiating changeback, as follows: * * i) individually for each traffic flow (i.e. on destination basis); * * ii) individually for each alternative signalling link (i.e. for all the * destinations previously diverted on that alternative signalling link); * * iii) at the same time for a number of, or for all the alternative signalling * links. * * On occurence of changeback, it may happen that traffic towards a given destination is no * longer routed via a given adjacent signalling transfer point, towards which a * transfer-prohibited procedure was previously performed on occurence of changeover (see * 5.3.1); in this case a transfer-allowed procedure is performed, as specified in 13.3. * * In addition, if traffic towards a given destination is diverted to an alternative * signalling link terminating in a signalling transfer point not currently used to carry * traffic toward that destination, a transfer-prohibited procedure is performed as * specified in 13.2. * * 6.2.2 In the case when there is no traffic to transfer to the signalling link made * available, none of the previous actions are performed. * * 6.2.3 In the case that the signalling link made available can be used to carry * signalling traffic towards a non-adjacent destination which was previously declared * inacessible, the following actions apply: * * i) the routing of the concerned signalling traffic is unblocked and transmission of * the concerend messages (if any) is started on the link made available; * * ii) an indication is sent to the User Part(s) (if any) to restart the concerned * signalling traffic; * * iii) the transfer-allowed procedure is performed, as specified in 13.3. However, in * national networks, when the recovered link is not on the normal route for that * destination, the transfer- restricted procedure may be performed as specified in * 13.4; * * iv) the transfer-prohibited procedure is performed as specified in 13.2.2 i). * * 6.2.4 In the case that the signalling link made available will be the first link to be * used on the normal route towards a destination previously declared restricted, the status * of the route is changed to available and the transfer-allowed procedure is performed as * specified in 13.3. * * 6.2.5 If the signalling point at the far end of the link made available currently is * inaccessible, from the signalling point initiating changeback (see clause 9 on MTP * Restart), the sequence control procedure specified in 6.3 (which requires communication * between the two concerned signalling points) does not apply, instead, the time-controlled * diversion specified in 6.4 is performed. This is made also when the concerned signalling * points are accessible, but there is no signalling route to it using the same outgoing * signalling link(s) (or one of the same slgnalling links) from which traffic will be * diverted. * * The time-controlled diversion procedure may also be used for the changeback between * different link sets instead of the sequence control procedure in order to avoid possible * message mis-sequencing (see Note) or problems with multiple parallel changebacks. * * NOTE -- The sequence control procedure can only guarantee correct sequencing of MSUs in * all cases if the alternative link terminates in the same signalling point (i.e. the * destination of the changeback declaration) as the newly available one. * * 6.3 Sequence control procedure * * 6.3.1 When a decision is made at a given signalling point to divert a given traffic * flow (towards one or more destinations) form an alternative singalling link to a * signalling link made available, the following actions are performed if possible (see * 6.4): * * i) transmission of the concerned traffic on the alternative signalling link is * stopped; such traffic is stored in a changeback buffer. * * ii) a changeback declaration is sent to the remote signalling point of the signalling * link made available via the concerned alternative siginalling link; this message * indicates that no more message signal units relating to the traffic being * diverted to the link made available will be sent on the alternative signalling * link. * * 6.3.2 The concerned signalling point will restart diverted traffic over the signalling * link made available when it receives a changeback acknowledgement from the far signalling * point of the link made availble; this message indicates that all signal messages relating * to the concerned traffic flow and routed to the remote signalling point via the * alternative signalling link have been received. The remote signalling point will send * the changeback acknowledgement to the signalling point initiating changeback in response * to the changeback declaration; any available signalling route between the two signalling * points can be used to carry the changeback acknowledgement. * * 6.3.3 The changeback declaration and changeback acknowledgment are signalling network * management messages and contain: * * - the label, indicating the destination and originating signalling points, and the * identity of the signalling link to which traffic will be diverted. * * - the changeback-declaration (or changeback-acknowledgement) signal; and * * - the changeback code. * * Formats and codes of the changeback-declaration and changeback-acknowledgement appear in * clause 15. * * 6.3.4 A particular configuration of the changeback code is autonomously assiged to the * changeback declaration by the signalling point initiating changeback; the same * configuration is included in the changeback acknowledgement by the acknowledging * signalling point. This allows discrimination between different changeback declarations * and acknowledgements when more than one sequence controll procedures are initiated in * parallel, as follows. * * 6.3.5 In the case that a signalling point intends to initiate changeback in parallel * for more than one alternative signalling link, a sequence control procedure is * accomplished for each involved signalling link, and a changeback-declaration is sent on * each of them; each changeback-declaration is assigned a different configuration of the * changeback code. Stopped traffic is stored in one or more changeback buffers (in the * latter case, a changeback buffer is provided for each alternative signalling link). When * the changeback-acknowledgement relating to that alternative signalling link is received, * traffic being diverted from a given alternative signalling link can be restarted on the * signalling link made available, starting with the content of the changeback buffer, * discrimination between the different changeback-acknowledgements is made by the * changeback code configuration, which is the same as that sent in the * changeback-declaration. * * The procedure allows either reopening the recovered singalling link to traffic in a * selective manner (provided that different changeback buffers are used) as soon as each * changeback-acknowledgement is received, or only when all the changeback-acknowledgements * have been received. * * 6.4 Time-controlled diversion procedure * * 6.4.1 The time-controlled diversion procedure is used at the end of the MTP restart * procedure (see clause 9) when an adjacent signalling point becomes available, as well as * for the reasons given in 6.2.5. An example of such a use appears in Figure 12. * * In this example, on failure of signalling link AB, traffic towards the destination D was * directed signalling link AC. When AB becomes available, the point A considers itself as * the neighbour of a point which restarts and applies the MTP restart procedure (see clause * 9). * * 6.4.2 When changeback is initiated after the MTP restart procedure, the adjacent * signalling point of the point whose MTP is restarting stops traffic to be directed from * the alternative signalling link(s) for a time T3, after which it starts traffic on the * signalling link(s) made available. The time delay minimizes the probability of out-of- * sequence deliver to the destination point(s). * * 6.5 Procedures in abnormal conditions * * 6.5.1 If a changeback-acknowledgement is received by a signalling point which has not * previously sent a changeback-declaration, no action is taken. * * 6.5.2 If a changeback-declaration is received after the completion of the changeback * procedure, a changeback-acknowledgement is sent in reponse, without taking any further * action. This corresponds to the normal action described in 6.3.2 above. * * 6.5.3 If no changeback-acknowledgement is received in response to a changeback * declaration with a time T4 (see 16.8), the changeback-declaration is repeated and a new * timer T5 (see 16.8) is started. If no changeback-acknowledgement is received before the * expiry of T5, the maintenance function are alterted and traffic on the link made * available is started. The changeback code contained in the changeback-acknowledgement * message makes it possible to determine, in the case of parallel changebacks from more * than one reserve path, which changeback-declaration is unacknowledged and has therefore * to be repeated. */ /* * Initiate changeback procedure on a siginalling link per Q.704 (07/96) * 6.2.1. */ static void link_up(struct ss7_link *link, __u8 reason) { if ( !(link->flags & SS7_LINK_DONTUSE) ) { link->flags &= ~reason; return; } /* * If we are performing a changeover, cancel per Q.704 (07/96) Figure * 30/Q.704 (sheet 3 of 6). */ if ( link->flags & SS7_LINK_CHANGEOVER ) { if ( link->cob_state == SS7_LK_COB_RETRIEVING ) { link->flags |= SS7_LINK_CHANGEBACK; link->reason = reason; return; /* wait for retrieval to finish */ } else { link->flags &= ~reason; changeover_abort(link); return; } } link->flags |= SS7_LINK_CHANGEBACK; link->flags &= ~reason; /* perform changeback procedure */ { /* * If all of the routesets which have this linkset on a route to a * destination signalling point have another viable signalling route * which is of higher priority than the signalling route coming * available, then the signalling link coming available will not be * carrying traffic: divert signalling traffic to the newly available * signalling link immediately. */ ss7_route *ra; ss7_route *ru; for ( ra = link->linkset->routes ; ra ; ra = ra-> lset ) if ( !(ru = alt_route(ra)) || ra->priority <= ru->priority ) break; if ( !ra ) return changeback_divert(link); } { struct ss7mtp_cb *mtp = link->linkset->local->cb; if ( link->linkset->usable ) { /* * If there is another viable link in the linkset to which the * signalling link coming available belongs, use that link to * send the CBD message and do a sequence controlled changeback. */ struct sk_buff *skb; struct ss7_link *alt; if ( (alt = alt_link(link)) && (skb = mtp_alloc_skb(GFP_KERNEL)) ) { ss7mtp_msg *m = (ss7mtp_msg *)skb->nh.raw; m->pvar.mh.si = 0x0; /* snmm */ m->pvar.mh.ni = mtp->ni; m->pvar.mh.mp = 0x3; m->pvar.mh.rl.dpc = link->linkset->adjacent->addr; m->pvar.mh.rl.opc = link->linkset->local->addr; m->pvar.mh.rl.sls = link->index; m->pvar.mh.h0 = 0x1; /* chm */ m->pvar.mh.h1 = 0x3; /* cbd */ m->pvar.msg.cbd.cbc = 0x0; *(skb->data) = SS7_L2_PDU; skb->priority = TC_PRIO_BESTEFFORT; __skb_trim(skb, hdrlen + sizeof(m->pvar.msg.cbd)); link_output(skb, alt); link->alt = alt; link->skb = skb; del_timer(&link->t); link->t.data = (unsigned long)link; link->t.function = &mtp_t4_timeout; link->t.expires = jiffies + mtp->t4_value; add_timer(&link->t); return; } } #if 0 /* FIXME: I shouldn't (???) be peforming changeback * until after the MTP restart procedure has * completed. */ else { struct ss7_routeset *adj = link->linkset->adjacent; if ( adj-> flags & SS7_RS_PROHIBITED ) { /* * If the link coming available is the only * link in the linkset to an otherwise * unavailable signalling point, then we * must perform MTP restart procedure. */ adj-> flags |= SS7_RS_MTP_RESTART; adj-> flags &= ~SS7_RS_TRA_SENT; del_timer(&adj->tmr); adj->tmr.data = (unsigned long)link; adj->tmr.function = &mtp_t21_timeout; adj->tmr.expires = jiffies + mtp->t21_value; add_timer(&adj->tmr); } } #endif /* * If the link comining available is the only link in the linkset * (i.e. we would have to send the CBD via a transfer point), or we * cannot otherwise communicate with the adjacent signalling point * (e.g. no buffers), do a time-controlled changeback, per Q.704 * (07/96) 6.2.5. When the link comes available at L3, the MTP * restart procedure should be performed per Q.704 (07/96) clause 9. */ del_timer(&link->t); link->t.data = (unsigned long)link; link->t.function = &mtp_t3_timeout; link->t.expires = jiffies + mtp->t3_value; add_timer(&link->t); return; } } static __inline void link_congested(struct ss7_link *link, unsigned char cong_status) { link->cong_status = cong_status; link-> flags |= SS7_LINK_CONGESTED; } static __inline void link_congestion_ceased(struct ss7_link *link) { link->cong_status = 0; link-> flags &= ~SS7_LINK_CONGESTED; } static __inline void link_retrieval_complete(struct ss7_link *link) { if ( !(link-> flags & SS7_LINK_CHANGEOVER) || link->cob_state != SS7_LK_COB_RETRIEVING ) return; changeover_divert(link); } static __inline void link_retrieval_not_possible(struct ss7_link *link) { if ( !(link-> flags & SS7_LINK_CHANGEOVER) || link->cob_state != SS7_LK_COB_RETRIEVING ) return; skb_queue_purge(&link->rtrvb); changeover_divert(link); } static __inline void link_retrieved_messages(struct ss7_link *link, struct sk_buff *skb) { struct sk_buff *skb0; if ( !(link->flags & SS7_LINK_CHANGEOVER) || link->cob_state != SS7_LK_COB_RETRIEVING ) return; if ( !(skb0 = skb_clone(skb, GFP_KERNEL)) ) return link_retrieval_not_possible(link); skb_queue_tail(&link->rtrvb, skb0); return; } static __inline void link_rb_cleared(struct ss7_link *link) { (void)link; return; } static __inline void link_bsnt(struct ss7_link *link, unsigned char bsnt) { if ( !(link-> flags & SS7_LINK_CHANGEOVER) || ( link->cob_state != SS7_LK_COB_BSNT_REQ_COO && link->cob_state != SS7_LK_COB_BSNT_REQ_COA ) ) return; link->loc_bsnt = bsnt | 0x80; if ( link->skb ) { struct ss7mtp_cb *mtp = link->linkset->local->cb; ss7mtp_msg *m = (ss7mtp_msg *)link->skb->nh.raw; struct sk_buff *skb = link->skb; switch (link->cob_state) { case SS7_LK_COB_BSNT_REQ_COO: m->pvar.mh.h0 = 0x1; m->pvar.mh.h1 = 0x1; /* coo */ m->pvar.msg.coo.fsnl = bsnt; *(skb->data) = SS7_L2_PDU; skb->priority = TC_PRIO_BESTEFFORT; __skb_trim(skb, hdrlen + sizeof(m->pvar.msg.coo)); link->cob_state = SS7_LK_COB_WAITING_ACK; link_output(link->skb, link->alt); del_timer(&link->t); link->t.data = (unsigned long)link; link->t.function = &mtp_t2_timeout; link->t.expires = jiffies + mtp->t2_value; add_timer(&link->t); break; case SS7_LK_COB_BSNT_REQ_COA: m->pvar.mh.h0 = 0x1; m->pvar.mh.h1 = 0x2; /* coa */ m->pvar.msg.coa.fsnl = bsnt; *(skb->data) = SS7_L2_PDU; skb->priority = TC_PRIO_BESTEFFORT; __skb_trim(skb, hdrlen + sizeof(m->pvar.msg.coa)); link_output(link->skb, link->alt); changeover_retrieval(skb,link); break; } kfree_skb(link->skb); link->skb = NULL; } return; } static __inline void link_in_service(struct ss7_link *link) { if ( !(link->flags & SS7_LINK_OUT_OF_SERVICE) ) return; del_timer(&link->t); /* stop T17 if its running */ /* * Signalling link must pass an exchange of SLTM/SLTA * before it is put into service at L3. */ link->flags |= SS7_LINK_TEST; send_sltm(link); } static __inline void link_out_of_service(struct ss7_link *link) { if ( link->flags & SS7_LINK_OUT_OF_SERVICE ) { /* * Restoration failed, follow procedures in Q.704 (07/96) 12.2.2 to * further attempt to restore link after time T17. */ ss7mtp_cb *mtp = link->linkset->local->cb; del_timer(&link->t); link->t.data = (unsigned long)link; link->t.function = &mtp_t17_timeout; link->t.expires = jiffies + mtp->t17_value; add_timer(&link->t); return; } link_down(link, SS7_LINK_OUT_OF_SERVICE); } static __inline void link_remote_processor_outage(struct ss7_link *link) { link_down(link, SS7_LINK_BLOCKED); return; } static __inline void link_remote_processor_recovered(struct ss7_link *link) { link_up(link, SS7_LINK_BLOCKED); return; } static __inline void link_rtb_cleared(struct ss7_link *link) { (void)link; /* FIXME: make this doooo something */ return; } void ss7mtp_input(struct sk_buff *skb) { /* ok, I have an mtp message from L2: what do I do with it ? */ unsigned char cmd = skb->data[0]; struct ss7_linkset *ls; struct ss7_link *link; struct ss7mtp_cb *mtp; if (!skb->dev) goto bad_control; if (!skb->dev->ss7_ptr) goto bad_control; if (!(link = &((struct ss7_iface *)skb->dev->ss7_ptr)->link)) goto bad_control; if (!(ls = link->linkset)) goto bad_control; if (!ls->local) goto bad_control; if (!(mtp = ls->local->cb)) goto bad_control; /* ok, we have an mtp control block identified, check what kind of message * */ switch (cmd) { case SS7_L3_PDU: skb_pull(skb, 4); /* command fsn/fib bsn/bib and li */ mtp->input(mtp, skb); break; case SS7_L3_LINK_CONGESTED: link_congested(link, skb->data[1]); break; case SS7_L3_LINK_CONGESTION_CEASED: link_congestion_ceased(link); break; case SS7_L3_RETRIEVED_MESSAGES: link_retrieved_messages(link, skb); break; case SS7_L3_RETRIEVAL_COMPLETE: link_retrieval_complete(link); break; case SS7_L3_RB_CLEARED: link_rb_cleared(link); break; case SS7_L3_BSNT: link_bsnt(link, skb->data[1]); break; case SS7_L3_IN_SERVICE: link_in_service(link); break; case SS7_L3_OUT_OF_SERVICE: link_out_of_service(link); break; case SS7_L3_REMOTE_PROCESSOR_OUTAGE: link_remote_processor_outage(link); break; case SS7_L3_REMOTE_PROCESSOR_RECOVERED: link_remote_processor_recovered(link); break; case SS7_L3_RTB_CLEARED: link_rtb_cleared(link); break; default: goto bad_control; } /* * Note: although the above calls to not consume the skb, they do in some * circumstances modify it. */ kfree_skb(skb); return; bad_control: /* log and peg */ kfree_skb(skb); return; }