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_spp.c#ident "@(#) $RCSfile: ua_spp.c,v $ $Name: $($Revision: 0.8.2.2 $) $Date: 2003/04/03 19:51:46 $" static char const ident[] = "$RCSfile: ua_spp.c,v $ $Name: $($Revision: 0.8.2.2 $) $Date: 2003/04/03 19:51:46 $"; #define __NO_VERSION__ #include <linux/config.h> #include <linux/version.h> #ifdef MODVERSIONS #include <linux/modversions.h> #endif #include <linux/module.h> #include <sys/stream.h> #include <sys/stropts.h> #include <sys/cmn_err.h> #include "../debug.h" #include "../bufq.h" #include "../ua/ua_data.h" #include "../ua/ua_msg.h" //#include "../ua/ua_sm.h" /* * ========================================================================= * * UA Peer --> UA (SPP) Received Messages * * ========================================================================= * * These are procedures for common UA received messages at the SPP. */ /* * ASPS ASPUP * ------------------------------------------------------------------------- * ASP Identifier Optional (But must be used sometimes) * ASP Capabilities Optional * Info String Optional */ static int ua_recv_aspup_req(spp_t * spp, mblk_t * mp) { pp_t *pp = (pp_t *) q->q_ptr; sp_t *sp = pp->u.sp; mblk_t *rp; struct ua_parm *aspid = &ua_parm_results.aspid; struct ua_parm *asp_caps = &ua_parm_results.asp_caps; ua_decode_parms(mp); if (!aspid->u.wptr) { if (!sp || !sp->aspid) { if (!(rp = ua_mgmt_err(SUA_ECODE_REFUSED_ASP_IDENTIFIER_REQUIRED))) return (-ENOBUFS); qreply(q, rp); return (-EINVAL); } } else { if (sp) { if (sp->lp || (sp->aspid && sp->aspid != aspid->val)) { if (!(rp = ua_mgmt_err(SUA_ECODE_ERROR_INVALID_ASP_IDENTIFIER))) return (-ENOBUFS); qreply(q, rp); return (-EINVAL); } } else { for (sp = asp_head; sp && sp->aspid != aspid->val; sp = sp->next); if (!sp) for (sp = sgp_head; sp && sp->aspid != aspid->val; sp = sp->next); if (!sp) for (sp = spp_head; sp && sp->aspid != aspid->val; sp = sp->next); if (!sp || sp->lp) { if (!(rp = ua_mgmt_err(SUA_ECODE_ERROR_INVALID_ASP_IDENTIFIER))) return (-ENOBUFS); qreply(q, rp); return (-EINVAL); } pp->u.sp = sp; sp->lp = pp; } sp->aspid = aspid->val; } if (!asp_caps->u.wptr) { if (sp->asp_caps) *(asp_caps->u.wptr) = htonl(sp->asp_caps); } else { if (sp->asp_caps) { if (sp->asp_caps != asp_caps->val) *(asp_caps->u.wptr) = htonl(sp->asp_caps); } else sp->asp_caps = asp_caps->val; } sp->state = ASP_STATE_INACTIVE; if ((err = asp_recalc_as_state(sp))) return (err); *((long *) mp->b_rptr) = SUA_ASPS_ASPUPAC; qreply(q, mp); return (0); } /* * ASPS ASPUP Ack * ------------------------------------------------------------------------- * ASP Identifier Optional (But must be used sometimes) * ASP Capabilities Optional * Info String Optional */ static int ua_recv_aspup_ack(spp_t * spp, mblk_t * mp) { int err; mblk_t *rp; pp_t *pp = (pp_t *) q->q_ptr; sp_t *sp = pp->u.sp; if (!sp || sp->state != ASP_STATE_WACK_ASPUP) { if (!(rp = ua_mgmt_err(SUA_ECODE_UNEXPECTED_MESSAGE))) return (-ENOBUFS); qreply(q, rp); return (-EINVALID); } /* * Can we use ASP Identifier and Capabilities to show SGP identity * and capabilies? Probably not. Just check if the ASP is in the * ASP_STATE_WACK_ASPUP state and move it to the ASP_STATE_INACTIVE. * Recalculate the state of all configured AS. It might be a good * idea not to "lock in" the AS state until we get an NTFY * (AS_STATE). */ if ((err = asp_recalc_as_state(sp))) return (err); sp->state = ASP_STATE_INACTIVE; freemsg(mp); return (0); } /* * ASPS ASPDN * ------------------------------------------------------------------------- */ static int ua_recv_aspdn_req(spp_t * spp, mblk_t * mp) { /* * This ASP is toast. Return ASPDN Ack and mark ASP_STATE_DOWN. * Recalculate AS status. */ freemsg(mp); return (0); } /* * ASPS ASPDN Ack (Watch this one for SUA and M3UA...) * ------------------------------------------------------------------------- */ static int ua_recv_aspdn_ack(spp_t * spp, mblk_t * mp) { /* * If we get this it does not matter that we are in what state. * if we are in ASP_STATE_WACK_ASPDN, then everything is fine. * However, if we are in any other state, we need to move to * the ASPDN state and then, errr.... Nope. That's just M3UA. */ freemsg(mp); return (0); } /* * ASPS HBEAT * ------------------------------------------------------------------------- * Heartbeat Data Optional */ static int ua_recv_hbeat_req(spp_t * spp, mblk_t * mp) { /* * This is a simple matter of turning around the heartbeat request. * We can just jam the message type and send it back. Don't even * pull out the parameters. */ (void) q; (void) mp; return (-EOPNOTSUPP); } /* * ASPS HBEAT Ack * ------------------------------------------------------------------------- * Heartbeat Data Optional */ static int ua_recv_hbeat_ack(spp_t * spp, mblk_t * mp) { /* * Check the heartbeat data. There are a number of occasions for * which we send heartbeats. There is a process waiting for the * response based on the heartbeat data or there is not. This needs * be done in parallel for some applications (changeback). We should * have a process list with ids from the data. That way we could use * the data to index the function to call here... * * Well..., normally we do this to flush an routing context traffic * flow. If there is heartbeat data, extract the routing contexts * out of the heartbeat data and find AS in the AS_WACK_BEAT state. */ (void) q; (void) mp; return (-EOPNOTSUPP); } /* * ASPT ASPAC * ------------------------------------------------------------------------- * Traffic Mode Type Mandatory * Routing Context Optional * INFO String Optional */ static int ua_recv_aspac_req(spp_t * spp, mblk_t * mp) { int i; struct ua_parm *rc = &ua_parm_results.rc; ua_decode_parm_results(mp); if (rc->u.wptr && rc->len > 4) { int i; uint32_t *p = rc->u.wptr; for (i = 0, p = rc->u.wptr; i < (rc->len / 4) - 1; i++, p++) { uint32_t rcval = ntohl(*p++); /* * Perform the ASPAC procedures. Traffic Mode is * mandatory, but I don't care when I know the mode * of the AS from configuration data. We must return * either en ASPAC Ack or an ERR. Move the ASP to * active in the indicated AS. Well..., just move * the ASP to the ASP-ACTIVE state and make sure that * we have the AS in the ASPs AS list. Do a state * recalc on all the AS in the AS list. */ } } else { } freemsg(mp); return (0); } /* * ASPT ASPAC Ack * ------------------------------------------------------------------------- * Traffic Mode Type Mandatory * Routing Context Optional * INFO String Optional */ static int ua_recv_aspac_ack(spp_t * spp, mblk_t * mp) { int i; struct ua_parm *rc = &ua_parm_results.rc; ua_decode_parms(mp); if (rc->u.wptr && rc->len > 4) { int i; uint32_t *p = rc->u.wptr; for (i = 0, p = rc->u.wptr; i < (rc->len / 4) - 1; i++, p++) { uint32_t rcval = ntohl(*p++); /* * Check for AS which belong to the ASP by routing * context. Find AS in the AS_WACK_ASPAC state. * Move them to the AS_ACTIVE state. I don't know * what the purpose of the returned traffic mode * type is... Is this the mode of the SGP? */ } } else { } freemsg(mp); return (0); } /* * ASPT ASPIA * ------------------------------------------------------------------------- * Routing Context Optional * INFO String Optional */ static int ua_recv_aspia_req(spp_t * spp, mblk_t * mp) { int i; struct ua_parm *rc = &ua_parms.rc; ua_decode_parms(mp); if (rc->u.wptr && rc->len > 4) { int i; uint32_t *p = rc->u.wptr; for (i = 0, p = rc->u.wptr; i < (rc->len / 4) - 1; i++, p++) { uint32_t rcval = ntohl(*p++); /* * Check for AS which belong to the ASP by routing * context. Place them in the state * AS_STATE_INACTIVE. ALWAYS respond with an ASPIA * Ack. Put it back if we can't. */ } } else { } freemsg(mp); return (0); } /* * ASPT ASPIA Ack * ------------------------------------------------------------------------- * Routing Context Optional * INFO String Optional */ static int ua_recv_aspia_ack(spp_t * spp, mblk_t * mp) { int i; struct ua_parm *rc = &ua_parms.rc; ua_decode_parms(mp); if (rc->u.wptr && rc->len >= 4) { int i; uint32_t *p = rc->u.wptr; for (i = 0, p = rc->u.wptr; i < (rc->len / 4) - 1; i++, p++) { uint32_t rcval = ntohl(*p++); /* * Find the RC in the list of AS which belong to this * ASP and see if it is in the state AS_STATE_WACK_ASPIA. * If it is, put it in the state AS_STATE_INACTIVE. */ } } else { /* * RC was not provided. This is the default routing context * case. Do we only have one AS? Only one AS in the * AS_STATE_WACK_ASPIA? */ } freemsg(mp); return (0); } /* * MGMT ERR * ------------------------------------------------------------------------- * Error Code Mandatory * Diagnostic Info Optional */ static int ua_recv_err(spp_t * spp, mblk_t * mp) { sp_t *sp = ((pp_t *) q->q_ptr)->u.sp; ua_decode_parms(mp); if (!ua_parms.ecode.u.wptr) return -EINVAL; switch (ua_parms.ecode.val) { /* * These values are from ua-07. */ case 0x01: /* Invalid Version */ case 0x05: /* Unsupported Traffic Handling Mode */ case 0x08: /* Invalid Routing Context */ /* * If I am trying something, give up. */ case 0x0c: /* Unexpected Parameter */ /* * TODO: Might be because we a using an extension * that the other end doesn't recognize. Go after * the diagnostics parameter and see if we get the * parameter. Then see if we can discover features * of the other end from which parameter was * unexpected. */ default: case 0x02: /* n/a */ case 0x03: /* Unexpected Message Class */ case 0x04: /* Invalid Message Type Class */ case 0x06: /* Unexpected Message */ case 0x07: /* Protocol Error */ case 0x09: /* Invalid Stream Identifier */ case 0x0b: /* Parameter Field Error */ case 0x0d: /* Duplicated Parameter */ case 0x0e: /* Error - ASP Identifier Required */ case 0x0f: /* Error - Invalid ASP Identifier */ case 0x10: /* Refused - ASP Identifier Required */ /* * Some of these can't happen (we always send * optional fields). Don't give up. */ } /* * TODO: Notify management. */ freemsg(mp); return (0); /* * MGMT ERR * ------------------------------------------------------------------------- * IMPLEMENTATION NOTE:- We want to report all errors to management. Some * errors are considered fatal errors. That is we will stop all processes, * and put everything associated with the ASP/SGP/SP into the Down state, * even drop the SCTP association. */ static int m3ua_err(spp_t * spp, mblk_t * mp) { m3ua_parms_t parms; parm_t *ecode = &parms->common.ecode; parm_t *diag = &parms->common.diag; m3ua_decode_parms(msg, &parms); if (!ecode->u.wptr) { /* missing mandatory parameter */ return (-EINVAL); } switch (*ecode->u.wptr) { case UA_ECODE_INVALID_VERSION: case UA_ECODE_INVALID_IID_OR_NTWK_APP: case UA_ECODE_UNSUPPORTED_MESSAGE_CLASS: case UA_ECODE_UNSUPPORTED_MESSAGE_TYPE: case UA_ECODE_UNSUPPORTED_TRAFFIC_MODE: case UA_ECODE_UNEXPECTED_MESSAGE: case UA_ECODE_PROTOCOL_ERROR: case UA_ECODE_INVALID_ROUTING_CONTEXT: case UA_ECODE_INVALID_STREAM_IDENTIFIER: case UA_ECODE_INVALID_PARAMETER_VALUE: case M3UA_ECODE_REFUSED_MANAGEMENT_BLOCKING: case M3UA_ECODE_UNKNOWN_ROUTING_CONTEXT: case M3UA_ECODE_INVALID_ASPID: default: /* error invalid error???? */ return (-EINVAL); } return (-EOPNOTSUPP); } } /* * MGMT NTFY * ------------------------------------------------------------------------- * Status Mandatory * ASP Identifier Optional * Routing Context Optional * Info String Optional */ static int ua_recv_ntfy(spp_t * spp, mblk_t * mp) { int i, err = 0; uint32_t *rc; struct ua_parm *rc = &ua_parm_results.rc; struct ua_parm *aspid = &ua_parm_results.aspid; sp_t *sp = ((pp_t *) q->q_ptr)->u.sp; ua_decode_parms(mp); if (!ua_parm_results.status.u.wptr) return -EINVAL; switch (ua_parm_results.status.val) { case 0x00010001: /* Application Server Down (AS-Down) */ err = ua_ntfy_as_state_change(q, rc, AS_STATE_DOWN); break; case 0x00010002: /* Application Server Inactive (AS-Inactive) */ err = ua_ntfy_as_state_change(q, rc, AS_STATE_INACTIVE); break; case 0x00010003: /* Application Server Active (AS-Active) */ err = ua_ntfy_as_state_change(q, rc, AS_STATE_ACTIVE); break; case 0x00010004: /* Application Server Pending (AS-Pending) */ err = ua_ntfy_as_state_change(q, rc, AS_STATE_PENDING); break; case 0x00020001: /* Insufficient ASP resources active in AS */ err = ua_ntfy_too_few_asps(q, rc, aspid); break; case 0x00020002: /* Alternative ASP Active */ err = ua_ntfy_alternate_asp(q, aspid); break; case 0x00020003: /* ASP Failure */ err = ua_ntfy_asp_failure(q, aspid); break; case 0x00020004: /* Minimum ASP resources active in AS */ err = ua_ntfy_as_vulnerable(q, rc); break; } if (err) return (err); freemsg(mp); return (0); } /* * MGMT NTFY * ------------------------------------------------------------------------- * IMPLEMENTATION NOTES:- Of these notifications, the changes in the state of * an Application Server as viewed by the SGP can be tracked at the ASP/IPSP. * Also, the change in state of specific ASP within the AS are indicated by * other notifications. We want to do two things with these notifications: * first, record the state change so that if we are later interrogated by the * application or layer management, we can report the current status of the * AS and ASPs within it, second, we inform both the application and layer * management of the state change. We take no other action. The reason we * take no other action is because we ae ill-equipped with custom * configuration information to determine within the kernel what the proper * response of the system is to these notifications. For example, if an we * are om the ASP_INACTIVE state with respect to an Application Server and we * get a NTFY(Minimum ASP resources available in AS) notification, the layer * manager may choose to start an application and have it activate the ASP * within the Application Server to reduce the vulnerability of the AS. * Booting applications is not something to be performed here... * * Actually, we don't care if the ASP Id or Routing Context is valid or not. * Let the application or layer manager figure that out. */ static int m3ua_ntfy(spp_t * spp, mblk_t * mp) { int i; as_t *as; uint event, state; uint muxid = Q_MUXID(q); m3ua_parms_t parms; parm_t *rc = &parms->common.rc; parm_t *aspid = &parms->common.aspid; parm_t *status = &parms->common.status; if (Q_MODE(q) == Q_MODE_SG) { /* unexpected message, AS do not notify SG */ return (-EINVAL); } if (!canput(m3ua_ctrlq)) return (-EBUSY); m3ua_decode_parms(msg, &parms); if (!status->u.wptr) { /* missing mandatory parameter */ return (-EINVAL); } if (rc->len > 0 && (rc->len & 0x3)) /* badly formatted parameter */ return (-EINVAL); switch (*status->u.wptr) { case UA_STATUS_AS_DOWN: event = ASE_DOWN; state = AS_DOWN; break; case UA_STATUS_AS_INACTIVE: event = ME_AS_INACTIVE; state = AS_INACTIVE; break; case UA_STATUS_AS_ACTIVE: event = ME_AS_ACTIVE; state = AS_ACTIVE; break; case UA_STATUS_AS_PENDING: event = ME_AS_PENDING; state = AS_PENDING; break; case UA_STATUS_AS_INSUFFICIENT_ASPS: event = ME_AS_CRITICAL; state = AS_CRITICAL; break; case UA_STATUS_ALTERNATE_ASP_ACTIVE: event = ME_ASP_OVERRIDE; state = -1; break; case UA_STATUS_ASP_FAILURE: event = ME_ASP_FAILURE; state = -1; break; case UA_STATUS_AS_MINIMUM_ASPS: event = ME_AS_VULNERABLE; state = AS_VULNERABLE; break; default: /* invalid status */ return (-EINVAL); } if (!rc->u.wptr || rc->len < sizeof(uint32_t)) { /* No routing contexts in message, is it implied? */ if (!(as = m3ua_as_default(q))) /* missing necessary routing context */ return (-EINVAL); if (lm_as_event_ind(muxid, event, as->id, aspid->val)) return (-ENOBUFS); if (state != -1) as->state = state; return (0); } for (i = 0; i < rc->len >> 2; i++) { if (!(as = m3ua_as_lookup(q, rc))) /* invalid routing context */ continue; if (lm_as_event_ind(muxid, event, as->id, aspid->val)) return (-ENOBUFS); if (state != -1) as->state = state; } return (0); } int (*ua_spp_mgmt[]) (spp_t *, mblk_t *) = { ua_recv_err, /* UA_MGMT_ERR 0x0 */ ua_recv_ntfy /* UA_MGMT_NTFY 0x1 */ }; int (*ua_spp_asps[]) (spp_t *, mblk_t *) = { NULL, /* (reserved) 0x0 */ ua_recv_aspup_req, /* UA_ASPS_ASPUP_REQ 0x1 */ ua_recv_aspdn_req, /* UA_ASPS_ASPDN_REQ 0x2 */ ua_recv_beat_req, /* UA_ASPS_HBEAT_REQ 0x3 */ ua_recv_aspup_ack, /* UA_ASPS_ASPUP_ACK 0x4 */ ua_recv_aspdn_ack, /* UA_ASPS_ASPDN_ACK 0x5 */ ua_recv_beat_ack /* UA_ASPS_HBEAT_ACK 0x6 */ }; int (*ua_spp_aspt[]) (spp_t *, mblk_t *) = { NULL, /* (reserved) 0x0 */ ua_recv_aspac_req, /* UA_ASPT_ASPAC_REQ 0x1 */ ua_recv_aspia_req, /* UA_ASPT_ASPIA_REQ 0x2 */ ua_recv_aspac_ack, /* UA_ASPT_ASPAC_ACK 0x3 */ ua_recv_aspia_ack /* UA_ASPT_ASPIA_ACK 0x4 */ };
|
|||||||||||||||||||||||||||
OpenSS7 SS7 for the Common Man |
Home | Overview | Status | News | Documentation | Resources | About | ||||||||||||||||||||
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |