OpenSS7 SS7 for the Common Man |
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |
||||||||||||||||||||||||||
Home | Overview | Status | News | Documentation | Resources | About | |||||||||||||||||||||
File /code/strss7/drivers/ua/ua_sm.c#ident "@(#) $RCSfile: ua_sm.c,v $ $Name: $($Revision: 0.8.2.1 $) $Date: 2002/10/18 02:26:20 $" static char const ident[] = "$RCSfile: ua_sm.c,v $ $Name: $($Revision: 0.8.2.1 $) $Date: 2002/10/18 02:26:20 $"; /* * ========================================================================= * * STATE MACHINE FUNCTIONS * * ========================================================================= * These are some state machine functions which are rather complicated and * need to be called from several places. These include state transitioning * for ASPs. */ /* * SG Blocked * ------------------------------------------------------------------------- * This function is called when an SGP encounters and error on a Routing * Context or Interface Id. It sends an ASPIA Ack to all connected ASPs for * the affected routing context and moves the ASPs to the ASP_INACTIVE state * for the affected AS. The function is called with an SG queue. * * What we are going to do here is send an ASPIA-Ack to all the ASPs for the * specified AS and mark the AS AS-BLOCKED. We should also send a NTFY * AS-Inactive to each of the inactive ASPs in the AS. This should freak the * ASPs into resending ASPAC. We unlink the stream and inform mangement. * Either the stream will be restored before the ASPAC arrives or we will * reject the ASPAC with an ERR message. As the AS is marked locally as * AS-BLOCKED any UA data messages received will be discarded. * * For M2UA, setting AS-BLOCKED means that acknowledgements of data messages * (Correlation Id Ack) and confirmations of MAUP messages will be * immediately suspended. */ int ua_ss7_blocked(queue_t * q) { gp_t *gp; mblk_t *mp, *np, *dp; static const char info[] = "Application Server blocked/failed at SG"; ensure(Q_TYPE(q) & Q_TYPE_SS7, return -EFAULT); ensure(Q_MODE(q) & Q_MODE_SG, return -EFAULT); ensure(sg->spac_count, return -EFAULT); if (Q_UA(q) & Q_UA_M2UA) { mp = ua_send_aspia_ack(&sg->list->rc.id, 1, NULL, 0, (caddr_t) info, info ? sizeof(info) - 1 : 0); np = ua_send_ntfy(UA_STATUS_AS_DOWN, NULL, &sg->list->rc.id, 1, NULL, 0, (caddr_t) info, info ? sizeof(info) - 1 : 0); } else { mp = ua_send_aspia_ack(NULL, 0, &sg->list->rc.id, 1, (caddr_t) info, info ? sizeof(info) - 1 : 0); np = ua_send_ntfy(UA_STATUS_AS_DOWN, NULL, NULL, 0, &sg->list->rc.id, 1, (caddr_t) info, info ? sizeof(info) - 1 : 0); } if (!mp || !np) { if (mp) freemsg(mp); if (np) freemsg(np); return (-ENOBUFS); } for (gp = sg->gp; gp; gp = gp->sp_next) { if (gp->state & (ASP_ACTIVE | ASP_INACTIVE)) { if (!(dp = dupmsg(np))) return (-ENOBUFS); ensure(gp->sp->lp, continue); /* FIXME: need SCTP stream selector on message */ putq(gp->sp->lp->q, dp); /* send it */ } if (gp->state & ASP_ACTIVE) { if (!(dp = dupmsg(mp))) return (-ENOBUFS); gp->state = ASP_INACTIVE; sg->spia_count++; sg->spac_count--; ensure(gp->sp->lp, continue); /* FIXME: need SCTP stream selector on message */ putq(gp->sp->lp->q, dp); /* send it */ } } sg->state = AS_BLOCKED; freemsg(mp); /* free original */ freemsg(np); /* free original */ q_disable(q); return (0); } /* * AS State Recalc * ------------------------------------------------------------------------- * An ASP has changed its state in this AS, so we need to recalculate the * current state of the AS and take appropriate actions. */ static void ua_as_state_recalc(as_t * as) { gp_t *gp; uint state = AS_DOWN; uint asps_ac = 0; uint asps_ia = 0; uint asps_dn = 0; for (gp = as->gp; gp; gp = gp->sp_next) { switch (gp->state & (ASP_DOWN | ASP_INACTIVE | ASP_ACTIVE)) { case ASP_DOWN: asps_dn++; break; case ASP_INACTIVE: asps_ia++; if (state == AS_DOWN) state = AS_INACTIVE; break; case ASP_ACTIVE: asps_ac++; state = AS_ACTIVE; break; } } if (state == AS_ACTIVE && asps_ac < as->min_count) { /* we don't have enough active asps */ state = AS_INACTIVE; if (as->state == AS_ACTIVE) { /* need to send notify to all inactive ASPs */ mblk_t *mp = msg_ntfy(UA_STATUS_AS_RESOURCE, as->iid); for (gp = as->list; gp; gp = gp->sp) if (gp->sp->state == ASP_INACTIVE) putq(WR(asp->q), dupmsg(mp)); freemsg(mp); } } if (as->state == AS_ACTIVE && state != AS_ACTIVE) { /* we need to push this ASP to the pending state */ state = AS_PENDING; /* * FIXME: set pending timer for this AS so that messages will * only be collected for a time. */ } as->state = state; as->asps_ac = asps_ac; as->asps_ia = asps_ia; as->asps_dn = asps_dn; return; } /* * ASP State Recalc * ------------------------------------------------------------------------- * An ASP has changed state so we need to recalculate the current state of * all of the AS of which the ASP is a part. */ static void ua_asp_state_recalc(asp_t * asp) { gp_t *gp; /* for each of the AS which own this ASP */ for (gp = asp->list; gp; gp = gp->node_next) ua_as_state_recalc(gp->node); return; } /* * SSP goes INACTIVE/DOWN within an SP * ------------------------------------------------------------------------- * An ASP/SGP/SPP has transitioned to the inactive (or down) state from the * active state within an AS/SG/SP. We must see what effect this has on the * caching of data routing and on the overall state of the AS. */ static void ua_sp_spp_inactive(sp_t * spp, sp_t * sp) { uint old_state = sp->state; switch (sp->tmode) { case UA_TMODE_OVERRIDE: switch (sp->state) { case AS_DOWN: case AS_ACTIVE: case AS_INACTIVE: case AS_PENDING: } case UA_TMODE_LOADSHARE: switch (sp->state) { case AS_DOWN: case AS_ACTIVE: case AS_INACTIVE: case AS_PENDING: } case UA_TMODE_BROADCAST: switch (sp->state) { case AS_DOWN: case AS_ACTIVE: case AS_INACTIVE: case AS_PENDING: } } /* inform all ASPs of any state changes */ if (old_state != sp->state) { mblk_t *mp; uint status; switch (sp->state) { case AS_DOWN: status = UA_STATUS_AS_DOWN; break; case AS_ACTIVE: status = UA_STATUS_AS_ACTIVE; break; case AS_INACTIVE: status = UA_STATUS_AS_INACTIVE; break; case AS_PENDING: status = UA_STATUS_AS_PENDING; break; } for (gp = spp->list; gp; gp = gp->node_next) { sl_t *} } return; } /* * SSP goes ACTIVE within an SP * ------------------------------------------------------------------------- * An ASP/SGP/SPP has transitioned to the active state from the inactive (or * down) state within an AS/SG/SP. We must see what effect this has on the * caching of data routing and on the overall state of the AS. */ static void ua_sp_spp_active(sp_t * spp, sp_t * sp) { switch (sp->tmode) { case UA_TMODE_OVERRIDE: switch (sp->state) { case UA_AS_DOWN: case UA_AS_ACTIVE: case UA_AS_INACTIVE: case UA_AS_PENDING: } case UA_TMODE_LOADSHARE: switch (sp->state) { case UA_AS_DOWN: case UA_AS_ACTIVE: case UA_AS_INACTIVE: case UA_AS_PENDING: } case UA_TMODE_BROADCAST: switch (sp->state) { case UA_AS_DOWN: case UA_AS_ACTIVE: case UA_AS_INACTIVE: case UA_AS_PENDING: } } return; } /* * SPP DOWN * ------------------------------------------------------------------------- * This includes all of the actions require to transition an SPP to the down * state from the current state at the serving SP. For example, this * includes all of the actions necessary to transition an ASP to the down * state at an SG. This function is called with the transport queue. */ static int ua_spp_down(queue_t * q) { sp_t *sp = Q_SP(q); if (sp->state & ASP_DOWN) return (0); switch (Q_MODE(q)) { case Q_MODE_SG: case Q_MODE_AS: case Q_MODE_SP: } if (m2p->state == ASP_DOWN) return; /* inform management that an ASP has gone down */ ua_asp_state_recalc(m2p); switch (m2p->state) { case UA_ASP_DOWN: /* already in down state: nothing to do */ return; case UA_ASP_INACTIVE: ua_asp_state_recalc(m2p->node); /* trivial, just transition the state and inform management */ break; case UA_ASP_ACTIVE: /* we must inform all owning SP of the loss of an active SPP */ { sp_t *sp; } break; } m2p->state = UA_ASP_DOWN; return; } /* * SPP UP * ------------------------------------------------------------------------- * This includes all of the actions necessary to transition an SPP to the up * state from the current state at the serving SP (with the exception of * sending peer pdus). */ static void ua_spp_up(queue_t * q) { sp_t *m2p = ((nsp_t *) q->q_ptr)->ua; sp_t *spp = m2p->list; } /* * SPP ACTIVE * ------------------------------------------------------------------------- * This includes all of the actions necessary to transition an SPP to the * active state from the current state at the serving SP (with the exception * of sending peer pdus). */ static void ua_spp_active(queue_t * q) { sp_t *m2p = ((nsp_t *) q->q_ptr)->ua; sp_t *spp = m2p->list; } /* * SPP INACTIVE * ------------------------------------------------------------------------- * This includes all of the actions necessary to transition an SPP to the * inactive state from the current state at the serving SP (with the * exception of sending peer pdus). */ static void ua_spp_inactive(queue_t * q) { sp_t *m2p = ((nsp_t *) q->q_ptr)->ua; sp_t *spp = m2p->list; } /* * SPP BLOCKED * ------------------------------------------------------------------------- * This includes all of the actions necessary to transition an SPP to the * down state from the current state when the SPP is blocked (the transport * provider has gone away). */ int ua_spp_blocked(queue_t * q) { sp_t *sp = Q_SP(q); mblk_t *mp, *np, *dp; if (sp->state & ASP_DOWN) return (0); switch (Q_MODE(q)) { case Q_MODE_SG: { static const char info[] = "Broken Pipe to ASP"; /* * The SG should mark the ASP down and send NTFY("ASP * Failure") to any inactive ASPs in the AS, to allow * another ASP to take over from this blocked ASP. */ np = ua_send_ntfy(UA_STATUS_ASP_FAILURE, &sp->id, NULL, 0, NULL, 0, (caddr_t) info, info ? sizeof(info) - 1 : 0); if (!np) return (-ENOBUFS); } case Q_MODE_AS: { static const char info[] = "Broken Pipe to ASP"; /* * The AS should */ } case Q_MODE_SP: { } default: return (-EFAULT); } /* * Change the state of the ASP within all ASs to ASP_DOWN. */ for (gp = sp->gp; gp; gp = gp->as_next) { as_t *as = gp->as; switch (gp->state) { case ASP_DOWN: continue; case ASP_INACTIVE: sp->aspia_count--; sp->aspdn_count++; gp->state = ASP_DOWN; break; case ASP_ACTIVE: sp->aspac_count--; sp->aspdn_count++; gp->state = ASP_DOWN; default: /* generate a SWERR */ gp->state = ASP_DOWN; continue; } /* * In each AS that the ASP has moved to ASP_DOWN, * recalculate the AS state and perform any changes. */ switch (as->state) { case AS_DOWN: case AS_INACTIVE: case AS_ACTIVE: case AS_PENDING: default: } } sp->state = ASP_DOWN; } /* * FIXME: Pulled these from old file.. figure out what to do with them... */ /* * ========================================================================= * * ASP State Machine procedures * * ========================================================================= */ static int ua_ntfy_as_state_change(queue_t * q, struct ua_parm *rc, uint state) { /* * NOTE: we have to go thru all the RCs in the list */ /* * An AS has changed state. We should mirror the change in the AS * state and determine if there is any action that we should take. * If the AS is in AS_STATE_PENDING, we may want to go active. If * the AS is in AS_STATE_INACTIVE we may want to go active. If the * AS is AS_STATE_ACTIVE we may want to do something else. */ } static int ua_ntfy_too_few_asps(q, rc) queue_t *q; struct ua_parm *rc; /* NULL if not specified */ { /* NOTE: we have to go thru all the rcs in the list */ } static int ua_ntfy_alternate_asp(q, aspid) queue_t *q; struct ua_parm *aspid; /* NULL if not specified */ { /* * We have been overridden. Perhaps we should say something to the * other asp which has (or may not) be identified. It would be nice * to have the ASP Id here as well. But it is not necessary. All * that we know is that we have been overridden. However, we are * still active, just not master. */ } static int ua_ntfy_asp_failure(q, rc, state) queue_t *q; struct ua_parm *aspid; /* NULL if not specified */ { if (!aspid->u.wptr) { /* * For ASP Failure we need to dig out the ASP Identifier. If * it is not there, the notificiation is pretty much useless. * Unless we want to go auditing. * * We want to return ERR Error - ASP Identifier Required */ return (-EINVAL); } /* * Mark out mate ASP with the specified id as failed. We may want to * take over its traffic if we are mirrored with it. */ } static int ua_ntfy_as_vulnerable(q, rc) queue_t *q; struct ua_parm *rc; /* NULL if not specified */ { /* * Some AS is running vulnerable. We should only get this * notification when we are inactive. We might want to activate * ourselves if we are next in line as a backup for the others. */ }
|
|||||||||||||||||||||||||||
OpenSS7 SS7 for the Common Man |
Home | Overview | Status | News | Documentation | Resources | About | ||||||||||||||||||||
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |