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/sigtran/ua_sgp.c#ident "@(#) $RCSfile: ua_sgp.c,v $ $Name: $($Revision: 0.8.2.3 $) $Date: 2003/04/14 12:13:20 $" static char const ident[] = "$RCSfile: ua_sgp.c,v $ $Name: $($Revision: 0.8.2.3 $) $Date: 2003/04/14 12:13:20 $"; #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 <sys/dki.h> #include "../debug.h" #include "../bufq.h" #include <sys/npi.h> #include <sys/npi_sctp.h> #include "../ua/ua_data.h" #include "sgp_data.h" #include "sgp_msg.h" #define SGP_DESCRIP "SIGTRAN SGP-Proxy STREAMS MULTIPLEXING DRIVER." #define SGP_COPYRIGHT "Copyright (c) 1997-2002 OpenSS7 Corporation. All Rights Reserved." #define SGP_DEVICE "Part of the OpenSS7 Stack for LiS STREAMS." #define SGP_CONTACT "Brian Bidulock <bidulock@openss7.org> #define SGP_LICENSE "GPL" #define SGP_BANNER SGP_DESCRIP "\n" \ SGP_COPYRIGHT "\n" \ SGP_DEVICE "\n" \ SGP_CONTACT "\n" MODULE_AUTHOR(SGP_CONTACT); MODULE_DESCRIPTION(SGP_DESCRIP); MODULE_SUPPORTED_DEVICE(SGP_DEVICE); #ifdef MODULE_LICENSE MODULE_LICENSE(SGP_LICENSE); #endif #ifndef INT #define INT void #endif /* * ========================================================================= * * STREAMS Definitions * * ========================================================================= */ static struct module_info sgp_u_minfo = { 0, /* Module ID number */ "sgp-lm", /* Module name */ 0, /* Min packet size accepted */ INFPSZ, /* Max packet size accepted */ 1, /* Hi water mark */ 0 /* Lo water mark */ }; static struct module_info sgp_l_minfo = { 0, /* Module ID number */ "sgp-n", /* Module name */ 0, /* Min packet size accepted */ INFPSZ, /* Max packet size accepted */ 1, /* Hi water mark */ 0 /* Lo water mark */ }; static int sgp_open(queue_t *, dev_t *, int, int, cred_t *); static int sgp_close(queue_t *, int, cred_t *); static INT sgp_u_wput(queue_t *, mblk_t *); static INT sgp_u_wsrv(queue_t *); static struct qinit sgp_u_winit = { sgp_u_wput, /* Write put (msg from above) */ sgp_u_wsrv, /* Write queue service */ NULL, /* Each open */ NULL, /* Last close */ NULL, /* Admin (not used) */ &sgp_u_minfo, /* Information */ NULL /* Statistics */ }; static INT sgp_u_rput(queue_t *, mblk_t *); static INT sgp_u_rsrv(queue_t *); static struct qinit sgp_u_rinit = { sgp_u_rput, /* Read put (msg from below) */ sgp_u_rsrv, /* Read queue service */ sgp_open, /* Each open */ sgp_close, /* Last close */ NULL, /* Admin (not used) */ &sgp_u_minfo, /* Information */ NULL /* Statistics */ }; static INT sgp_l_wput(queue_t *, mblk_t *); static INT sgp_l_wsrv(queue_t *); static struct qinit sgp_l_winit = { sgp_l_rput, /* Write put (msg from above) */ sgp_l_rsrv, /* Write queue service */ NULL, /* Each open */ NULL, /* Last close */ NULL, /* Admin (not used) */ &sgp_l_minfo, /* Information */ NULL /* Statistics */ }; static INT sgp_l_rput(queue_t *, mblk_t *); static INT sgp_l_rsrv(queue_t *); static struct qinit sgp_l_rinit = { sgp_l_rput, /* Read put (msg from below) */ sgp_l_rsrv, /* Read queue service */ NULL, /* Each open */ NULL, /* Last close */ NULL, /* Admin (not used) */ &sgp_l_minfo, /* Information */ NULL /* Statistics */ }; static struct streamtab sgp_info = { &sgp_u_rinit, /* Upper read queue */ &sgp_u_winit, /* Upper write queue */ &sgp_l_rinit, /* Lower read queue */ &sgp_l_winit /* Lower write queue */ }; /* * ========================================================================= * * OUTPUT EVENTS * * ========================================================================= */ /* * ------------------------------------------------------------------------- * * Buffer Allocation * * ------------------------------------------------------------------------- */ /* * BUFSRV calls service routine * ------------------------------------ */ static void ua_bufsrv(long data) { ua_t *ua = (ua_t *) data; if (ua->bid) { ua->bid = 0; qenable(ua->rq); qenable(ua->wq); } } /* * BUFCALL for enobufs * ------------------------------------ */ static int ua_bufcall(ua_t * ua, size_t size) { if (!ua->bid) ua->bid = bufcall(size, BPRI_MED, *ua_bufsrv, (long) ua); return (-ENOBUFS); } /* * REUSEB * ------------------------------------ * Attempt to reuse a mblk before allocating one. */ static int reuseb(ua_t * ua, size_t size, int prior, mblk_t ** mp) { int rtn; if (!(*mp) || (*mp)->b_datap->db_lim = (*mp)->b_datap->db_base < size) { rtn = 0; if (!((*mp) = allocb(size, prior))) return ua_bufcall(ua, size); } else { rtn = 1; if ((*mp)->b_cont) { freemsg((*mp)->b_cont); (*mp)->b_cont = NULL; } (*mp)->b_wptr = (*mp)->b_rptr = (*mp)->b_datap->db_base; } return (rtn); } /* * SGP LM Upstream Primitives * ----------------------------------- */ static int lm_ok_ack(ua_t * ua, mblk_t * mp, ulong prim) { int rtn; lm_ok_ack_t *p; if ((rtn = reuseb(ua, sizeof(*p), BPRI_MED, &mp)) >= 0) { p = ((typeof(p)) mp->b_wptr)++; mp->b_datap->db_type = M_PCPROTO; p->prim = LM_OK_ACK; p->correct_prim = prim; putnext(ua->mq, mp); } return (rtn); } static int lm_error_ack(ua_t * ua, mblk_t * mp, ulong prim, int err) { int rtn; lm_error_ack_t *p; if ((rtn = reuseb(ua, sizeof(*p), BPRI_MED, &mp)) >= 0) { p = ((typeof(p)) mp->b_wptr)++; mp->b_datap->db_type = M_PCPROTO; p->prim = LM_ERROR_ACK; p->error_prim = prim; p->errno = err < 0 ? LM_SYSERR : err; p->unix_error = err < 0 ? -err : 0; putnext(ua->mq, mp); } return (rtn); } static int lm_reg_ind(ua_t * ua, mblk_t * mp) { int rtn; lm_reg_ind_t *p; if ((rtn = reuseb(ua, sizeof(*p), BPRI_MED, &mp)) >= 0) { p = ((typeof(p)) mp->b_wptr)++; mp->b_datap->db_type = M_PCPROTO; p->prim = LM_REG_IND; p->muxid = ua->u.btm.muxid; p->aspid = FIXME; p->load = FIXME; p->prio = FIXME; p->KEY_number = FIXME; p->KEY_offset = FIXME; p->KEY_length = FIXME; putnext(ua->mq, mp); } return (rtn); } static int lm_dereg_ind(ua_t * ua, mblk_t * mp, ulong key) { int rtn; lm_dereg_ind_t *p; if ((rtn = reuseb(ua, sizeof(*p), BPRI_MED, &mp)) >= 0) { p = ((typeof(p)) mp->b_wptr)++; mp->b_datap->db_type = M_PCPROTO; p->prim = LM_DEREG_IND; p->muxid = ua->u.btm.muxid; p->KEY_number = key; putnext(ua->mq, mp); } return (rtn); } static int lm_error_ind(ua_t * ua, mblk_t * mp, int err) { int rtn; lm_error_ind_t *p; if ((rtn = reuseb(ua, sizeof(*p), BPRI_MED, &mp)) >= 0) { p = ((typeof(p)) mp->b_wptr)++; mp->b_datap->db_type = M_PCPROTO; p->prim = LM_ERROR_IND; p->muxid = ua->u.btm.muxid; p->errno = err < 0 ? LM_SYSERR : err; p->unix_error = err < 0 ? -err : 0; putnext(ua->mq, mp); } return (rtn); } /* * SGP N-Provider Downstream Primitives * ----------------------------------- */ static int n_data_req(ua_t * ua, mblk_t * mp, int ppi, int sid, int rcpt, mblk_t * dp) { int rtn; N_data_req_t *p; N_qos_sel_data_sctp_t *q; if ((mp = allocb(sizeof(*p) + sizeof(*q), BPRI_MED))) { p = ((typeof(p)) mp->b_wptr)++; mp->b_datap->db_type = M_PROTO; p->PRIM_type = N_DATA_REQ; p->DATA_xfer_flags = rcpt ? N_RC_FLAG : 0; q = ((typeof(q)) mp->b_wptr)++; q->n_qos_type = N_QOS_SEL_DATA_SCTP; q->ppi = ppi; q->sid = sid; q->ssn = 0; q->tsn = 0; q->more = 0; mp->b_cont = dp; putnext(ua->wq, mp); return (0); } return (-ENOBUFS); } static int n_exdata_req(ua_t * ua, mblk_t * mp, int ppi, int sid, int rcpt, mblk_t * dp) { int rtn; N_exdata_req_t *p; N_qos_sel_data_sctp_t *q; if ((mp = allocb(sizeof(*p) + sizeof(*q), BPRI_MED))) { p = ((typeof(p)) mp->b_wptr)++; mp->b_datap->db_type = M_PROTO; mp->b_band = 2; p->PRIM_type = N_EXDATA_REQ; q = ((typeof(q)) mp->b_wptr)++; q->n_qos_type = N_QOS_SEL_DATA_SCTP; q->ppi = ppi; q->sid = sid; q->ssn = 0; q->tsn = 0; q->more = 0; mp->b_cont = dp; putnext(ua->wq, mp); return (0); } return (-ENOBUFS); } static int n_discon_req(ua_t * ua, mblk_t * mp, ulong seq, void *res_ptr, size_t res_len) { int rtn; N_discon_req_t *p; if ((rtn = reuseb(ua, sizeof(*p) + res_len, BPRI_MED, &mp)) >= 0) { p = ((typeof(p)) mp->b_wptr)++; mp->b_datap->db_type = M_PCPROTO; p->PRIM_type = N_DISCON_REQ; p->DISCON_reason = 0; p->RES_length = res_len; p->RES_offset = res_len ? sizeof(*p) : 0; p->SEQ_number = seq; putnext(ua->wq, mp); } return (rtn); } /* * SGP message written for lower stream (need translating). */ static int sgp_mgmt_w_err(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_mgmt_w_ntfy(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_snmm_w_duna(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_snmm_w_dava(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_snmm_w_daud(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_snmm_w_scon(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_snmm_w_dupu(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_snmm_w_drst(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_asps_w_aspup_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_asps_w_aspdn_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_asps_w_hbeat_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_asps_w_aspup_ack(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_asps_w_aspdn_ack(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_asps_w_hbeat_ack(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_aspt_w_aspac_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_aspt_w_aspia_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_aspt_w_aspac_ack(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_aspt_w_aspia_ack(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_rkmm_w_reg_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_rkmm_w_reg_rsp(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_rkmm_w_dereg_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_rkmm_w_dereg_rsp(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } /* * ========================================================================= * * SGP State Machine * * ========================================================================= */ /* * ========================================================================= * * UA Peer --> UA (SGP) Received Messages * * ========================================================================= * * These are procedures for common UA received messages at the SGP. */ static int ua_recv_aspac_ack(queue_t * q, 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 SGP 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 Ack * ------------------------------------------------------------------------- * Routing Context Optional * INFO String Optional */ static int ua_recv_aspia_ack(queue_t * q, 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 * SGP 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(queue_t * q, 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(queue_t * q, 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(queue_t * q, 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(queue_t * q, 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); } /* * ========================================================================= * * INPUT EVENTS * * ========================================================================= */ /* * SGP message read for upper stream (need translating). */ static int sgp_mgmt_r_err(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_mgmt_r_ntfy(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_asps_r_aspup_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; as_t *as = ua->u.sp; } static int sgp_asps_r_aspdn_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } /* * ASPS HBEAT Req * ------------------------------------------------------------------------- * Heartbeat Data Optional */ static int sgp_asps_r_hbeat_req(queue_t * q, mblk_t * mp) { int err; mblk_t *rp; size_t mlen = mp->b_wptr - mp->b_rptr; ua_t *ua = (ua_t *) q->q_ptr; sgp_t *sgp = ua->u.spp; /* * 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. */ } /* * ASPS ASPUP Ack * ------------------------------------------------------------------------- * ASP Identifier Optional (But must be used sometimes) * Info String Optional */ static int sgp_asps_r_aspup_ack(queue_t * q, mblk_t * mp) { int err; size_t mlen = mp->b_wptr - mp->b_rptr; ua_t *ua = (ua_t *) q->q_ptr; sgp_t *sgp = ua->u.spp; if (sgp && sgp->state == ASP_WACK_ASPUP) { fixme(("We should also check that the ASPId is valid\n")); as->state = ASP_INACTIVE; if ((err = sgp_recalc_as_state(as))) { as->state = ASP_WACK_ASPUP; return (err); } fixme(("Notify LM of SGP UP with INFO string.\n")); return (0); } return ua_reply_mgmt_err(q, UA_ECODE_UNEXPECTED_MESSAGE, mp->b_rptr, mlen); } /* * ASPS ASPDN Ack * ------------------------------------------------------------------------- * Info Optional */ static int sgp_asps_r_aspdn_ack(queue_t * q, mblk_t * mp) { int err; size_t mlen = mp->b_wptr - mp->b_rptr; ua_t *ua = (ua_t *) q->q_ptr; sgp_t *sgp = ua->u.spp; if (sgp && sgp->state == ASP_WACK_ASPDN) { sgp->state = ASP_DOWN; if ((err = sgp_recalc_as_state(sgp))) { sgp->state = ASP_WACK_ASPDN; return (err); } fixme(("Notify LM of SGP DN with INFO string.\n")); return (0); } return ua_reply_mgmt_err(q, UA_ECODE_UNEXPECTED_MESSAGE, mp->b_rptr, mlen); } /* * ASPS HBEAT Ack * ------------------------------------------------------------------------- * Heartbeat Data Optional */ static int sgp_asps_r_hbeat_ack(queue_t * q, mblk_t * mp) { int err; size_t mlen = mp->b_wptr - mp->b_rptr; ua_t *ua = (ua_t *) q->q_ptr; sgp_t *sgp = ua->u.spp; /* * 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. */ if (sgp && sgp->state == ASP_WACK_BEAT) { sp->state = ASP_ACTIVE; fixme(("Process hbeat ack\n")); return (0); } return ua_reply_mgmt_err(q, UA_ECODE_UNEXPECTED_MESSAGE, mp->b_rptr, mlen); } static int sgp_aspt_r_aspac_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_aspt_r_aspia_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } /* * ASPT ASPAC Ack * ------------------------------------------------------------------------- * Traffic Mode Type Optional * Routing Context/IIDs Optional * INFO String Optional */ static int sgp_aspt_r_aspac_ack(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; sgp_t *sgp = ua->u.spp; struct ua_parm *rc = NULL; struct ua_parm *tmode = NULL; struct ua_parms_t parms; /* * IMPLEMENTATION NOTES:- The Traffic Mode Type parameter is * optional in the SGP Active Ack. Nowhere in any of the UA drafts * does it say what this parameter is supposed to contain nor what * the SGP is supposed to do with it. */ if ((err = ua_decode_parms(&parms, mp))) return (err); /* * M2UA uses IID, M2UA/ISUA/SUA/TUA use RC. */ if (parms.iid.u.wptr && parms.iid.len >= sizeof(rc->val)) rc = &parms.iid; else if (parms.rc.u.wptr && parms.rc.len >= sizeof(rc->val)) rc = &parms.rc; if (parms.tmode.u.wptr && parms.tmode.len >= sizeof(tmode->val)) tmode = &parms.tmode; if (rc) { /* * Walk through all of the RCs in the message and perform the * function on the associated AS. */ int i; uint32_t *p; for (i = 0, p = rc->u.wptr; i < (rc->len / 4) - 1; i++, p++) { uint32_t rcval = ntohl(*p); /* * Check for an AS which belongs to the SGP by * routing context. Find AS in the AS_WACK_ASPAC * state. Move them to the AS_ACTIVE state and stop * any t_ack timers. I don't know what the purpose * of the returned traffic mode type is... Is it the * mode of the SGP? */ gp_t *gp; for (gp = sgp->gp; gp && gp->sp->rc ==; gp = gp->sp_next) { } } } else { /* * Walk through all the AS assigned to the SGP and perform * the function for the associated AS. */ gp_t *gp; for (gp = sgp->gp; gp; gp = gp->sp_next) { as_t *as = gp->sp; if (!tmode || tmode->val == as->tmode) { switch (gp->state) { case ASP_INACTIVE: fixme(("Send an ERR message\n")); continue; case ASP_ACTIVE: case ASP_WACK_HBEAT: /* ignore */ continue; case ASP_WACK_ASPAC: gp->state = AS_ACTIVE; if (gp->t_ack) untimeout(xchg(&gp->t_ack, 0)); fixme(("Recalculate state\n")); continue; case ASP_WACK_ASPIA: fixme(("Send an ERR and another ASPIA\n")); continue; case ASP_DOWN: case ASP_WACK_ASPUP: case ASP_WACK_ASPDN: default: ptrace(("This is a software error\n")); continue; } } /* wrong traffic mode type */ } } /* * Dig out the RC/IIDs if any. If there are no RC/IIDs, then the * ASPAC Ack corresponds to all of the AS to which this SGP is * configured. * * Walk through the AS that correspond to the RC/IIDs. And perform * the ASPAC Ack procedure. If there are any invalid RC/IIDs, * respond to them with ERR messges indicating the RC/IID affected. * If the TMT is provided and is invalid for any of the RC/IIDs, * then response with appropriate ERR messages. */ if (sgp) { switch (sgp->state) { case ASP_DOWN: case ASP_INACTIVE: case ASP_WACK_BEAT: case ASP_WACK_ASPDN: case ASP_WACK_ASPUP: case ASP_WACK_ASPIA: case ASP_WACK_ASPAC: } } } static int sgp_aspt_r_aspia_ack(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_rkmm_r_reg_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_rkmm_r_reg_rsp(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_rkmm_r_dereg_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_rkmm_r_dereg_rsp(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int sgp_recv_msg(queue_t * q, mblk_t * mp) { switch (class) { case UA_CLASS_MGMT: switch (msgid) { case UA_MSGID_MGMT_ERR: case UA_MSGID_MGMT_NTFY: } break; case UA_CLASS_XFER: switch (msgid) { case UA_MSGID_XFER_DATA: } break; case UA_CLASS_SNMM: switch (msgid) { case UA_MSGID_SNMM_DUNA: case UA_MSGID_SNMM_DAVA: case UA_MSGID_SNMM_DAUD: case UA_MSGID_SNMM_SCON: case UA_MSGID_SNMM_DUPU: case UA_MSGID_SNMM_DRST: } break; case UA_CLASS_ASPS: switch (msgid) { case UA_MSGID_ASPS_ASPUP_REQ: case UA_MSGID_ASPS_ASPDN_REQ: case UA_MSGID_ASPS_HBEAT_REQ: case UA_MSGID_ASPS_ASPUP_ACK: case UA_MSGID_ASPS_ASPDN_ACK: case UA_MSGID_ASPS_HBEAT_ACK: } break; case UA_CLASS_ASPT: switch (msgid) { case UA_MSGID_ASPT_ASPAC_REQ: case UA_MSGID_ASPT_ASPIA_REQ: case UA_MSGID_ASPT_ASPAC_ACK: case UA_MSGID_ASPT_ASPIA_ACK: } break; case UA_CLASS_Q921: switch (msgid) { } break; case UA_CLASS_MAUP: switch (msgid) { case M2UA_MSGID_MAUP_DATA: case M2UA_MSGID_MAUP_ESTAB_REQ: case M2UA_MSGID_MAUP_ESTAB_CON: case M2UA_MSGID_MAUP_REL_REQ: case M2UA_MSGID_MAUP_REL_CON: case M2UA_MSGID_MAUP_REL_IND: case M2UA_MSGID_MAUP_STATE_REQ: case M2UA_MSGID_MAUP_STATE_CON: case M2UA_MSGID_MAUP_STATE_IND: case M2UA_MSGID_MAUP_RETR_REQ: case M2UA_MSGID_MAUP_RETR_CON: case M2UA_MSGID_MAUP_RETR_IND: case M2UA_MSGID_MAUP_RETR_COMP_IND: case M2UA_MSGID_MAUP_CONG_IND: case M2UA_MSGID_MAUP_DATA_ACK: } break; case UA_CLASS_CNLS: switch (msgid) { case SUA_MSGID_CNLS_CLDT: case SUA_MSGID_CNLS_CLDR: } break; case UA_CLASS_CONS: switch (msgid) { case SUA_MSGID_CONS_CORE: case SUA_MSGID_CONS_COAK: case SUA_MSGID_CONS_COREF: case SUA_MSGID_CONS_RELRE: case SUA_MSGID_CONS_RELCO: case SUA_MSGID_CONS_RESCO: case SUA_MSGID_CONS_RESRE: case SUA_MSGID_CONS_CODT: case SUA_MSGID_CONS_CODA: case SUA_MSGID_CONS_COERR: case SUA_MSGID_CONS_COIT: } break; case UA_CLASS_RKMM: switch (msgid) { case UA_MSGID_RKMM_REG_REQ: case UA_MSGID_RKMM_REG_RSP: case UA_MSGID_RKMM_DEREG_REQ: case UA_MSGID_RKMM_DEREG_RSP: } break; case UA_CLASS_TDHM: switch (msgid) { case TUA_MSGID_TDHM_UNI: case TUA_MSGID_TDHM_BEG: case TUA_MSGID_TDHM_CON: case TUA_MSGID_TDHM_END: case TUA_MSGID_TDHM_U_ABT: case TUA_MSGID_TDHM_P_ABT: case TUA_MSGID_TDHM_NOT: } break; case UA_CLASS_TCHM: switch (msgid) { case TUA_MSGID_TCHM_IVK: case TUA_MSGID_TCHM_RES: case TUA_MSGID_TCHM_U_ERR: case TUA_MSGID_TCHM_REJ: } break; } } /* * SGP LM Downstream Primitives * ----------------------------------- */ static int lm_as_add_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; size_t mlen = mp->b_wptr - mp->b_rptr; lm_as_add_req_t *p = (typeof(p)) mp->b_rptr; } static int lm_as_del_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; size_t mlen = mp->b_wptr - mp->b_rptr; lm_as_del_req_t *p = (typeof(p)) mp->b_rptr; } static int lm_proc_add_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; size_t mlen = mp->b_wptr - mp->b_rptr; lm_proc_add_req_t *p = (typeof(p)) mp->b_rptr; } static int lm_proc_del_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; size_t mlen = mp->b_wptr - mp->b_rptr; lm_proc_del_req_t *p = (typeof(p)) mp->b_rptr; } static int lm_link_add_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; size_t mlen = mp->b_wptr - mp->b_rptr; lm_link_add_req_t *p = (typeof(p)) mp->b_rptr; } static int lm_link_del_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; size_t mlen = mp->b_wptr - mp->b_rptr; lm_link_del_req_t *p = (typeof(p)) mp->b_rptr; } static int lm_route_add_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; size_t mlen = mp->b_wptr - mp->b_rptr; lm_route_add_req_t *p = (typeof(p)) mp->b_rptr; } static int lm_route_del_req(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; size_t mlen = mp->b_wptr - mp->b_rptr; lm_route_del_req_t *p = (typeof(p)) mp->b_rptr; } static int lm_reg_res(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; size_t mlen = mp->b_wptr - mp->b_rptr; lm_reg_res_t *p = (typeof(p)) mp->b_rptr; } /* * SGP N-Provider Upstream Primitives * ----------------------------------- */ static int n_data_ind(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; if ((err = sgp_recv_msg(ua, mp->b_cont))) return (err); mp->b_cont = NULL; return (0); } static int n_exdata_ind(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; if ((err = sgp_recv_msg(ua, mp->b_cont))) return (err); mp->b_cont = NULL; return (0); } static int n_datack_ind(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; return sgp_recv_ack(ua, mp); } /* * NOTE:- If we get any other indication or confirmation we are not prepared * to handle it. We error out the stream, place the message back on the * queue (for the configuration daemon to deal with), and disable the queue. * We notify the configuration daemon on the control stream (if possible) and * wait for the configuration daemon to unlink the stream and deal with * things. */ static int n_discon_ind(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; } static int n_reset_ind(queue_t * q, mblk_t * mp) { int rtn; ua_t *ua = (ua_t *) q->q_ptr; return n_discon_req(ua, mp, 0, NULL, 0); } static int n_other_ind(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; ptrace(("SGP received unexpected primitive %ld on lower RD(q) %d\n", *((long *) mp->b_rptr), ua->id.mux)); if ((err = ua_hangup(ua))) return (err); noenable(q); putbq(q, mp); return (0); } static int n_conn_ind(queue_t * q, mblk_t * mp) { int err; N_discon_req_t *p; (void) ua; (void) mp; ptrace(("SGP received N_CONN_IND on lower RD(q) %d\n", ua->id.mux)); fixme(("We need to error out the stream.\n")); return (-EFAULT); } static int n_conn_con(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; (void) ua; (void) mp; ptrace(("SGP received N_CONN_CON on lower RD(q) %d\n", ua->id.mux)); return (-EFAULT); } static int n_info_ack(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; (void) ua; (void) mp; ptrace(("SGP received N_INFO_ACK on lower RD(q) %d\n", ua->id.mux)); return (-EFAULT); } static int n_bind_ack(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; (void) ua; (void) mp; ptrace(("SGP received N_BIND_ACK on lower RD(q) %d\n", ua->id.mux)); return (-EFAULT); } static int n_error_ack(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; (void) ua; (void) mp; ptrace(("SGP received N_ERROR_ACK on lower RD(q) %d\n", ua->id.mux)); fixme(("We need to error out the stream.\n")); return (-EFAULT); } static int n_ok_ack(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; (void) ua; (void) mp; ptrace(("SGP received N_OK_ACK on lower RD(q) %d\n", ua->id.mux)); return (-EFAULT); } static int n_unitdata_ind(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; (void) ua; (void) mp; ptrace(("SGP received N_UNITDATA_IND on lower RD(q) %d\n", ua->id.mux)); return (-EFAULT); } static int n_uderror_ind(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; (void) ua; (void) mp; ptrace(("SGP received N_UDERROR_IND on lower RD(q) %d\n", ua->id.mux)); return (-EFAULT); } static int n_reset_con(queue_t * q, mblk_t * mp) { int err; ua_t *ua = (ua_t *) q->q_ptr; (void) ua; (void) mp; ptrace(("SGP received N_RESET_CON on lower RD(q) %d\n", ua->id.mux)); return (-EFAULT); } /* * ========================================================================= * * STREAMS Message Handling * * ========================================================================= */ /* * ------------------------------------------------------------------------- * * M_IOCDATA Handling * * ------------------------------------------------------------------------- */ static int sgp_u_w_iocdata(queue_t * q, mblk_t * mp) { (void) q; (void) mp; ptrace(("Received M_IOCDATA on upper WR(q)\n")); return (-EOPNOTSUPP); } /* * ------------------------------------------------------------------------- * * M_IOCTL Handling * * ------------------------------------------------------------------------- */ static ua_t *sgp_links_list = NULL; static int sgp_u_w_ioctl(queue_t * q, mblk_t * mp) { int err = EOPNOTSUPP; struct iocblk *iocp = (struct iocblk *) mp->b_rptr; switch (_IOC_TYPE(iocp->ioc_cmd)) { case __SID: { lp_t *lp; ua_t *ua = (ua_t *) q->q_ptr; struct linkblk *lb = (struct linkblk *) (mp->b_cont ? mp->b_cont->b_rptr : NULL); switch (iocp->ioc_cmd) { case I_PLINK: err = EPERM; if (iocp->ioc_cr->cr_uid != 0) break; case I_LINK: err = 0; if (lb->l_qbot->q_ptr != NULL) break; /* already linked */ if ((lp = kmem_cache_alloc(ua_pp_cachep, SLAB_ATOMIC))) { bzero(lp, sizeof(lp_t)); if ((lp->next = sgp_links_list)) lp->next->prev = &lp->next; lp->prev = &sgp_links_list; sgp_links_list = lp; lp->id.mux = lb->l_index; lp->rq = RD(lb->l_qbot); lp->wq = WR(lb->l_qbot); lp->mq = RD(q); lp->rq->q_ptr = lp->wq->q_ptr = lp; } err = ENOMEM; break; case I_PUNLINK: err = EPERM; if (iocp->ioc_cr->cr_uid != 0) break; case I_UNLINK: err = 0; if (!(lp = (lp_t *) lb->l_qbot->q_ptr)) break; /* already unlinked */ fixme(("More thinks to unlink\n")); if ((*(lp->prev) = lp->next)) lp->next->prev = lp->prev; lp->prev = NULL; lp->next = NULL; if (lp->bid) unbufcall(lp->bid); lp->rq->q_ptr = lp->wq->q_ptr = NULL; kmem_cache_free(ua_pp_cachep, lp); qenable(lp->rq); qenable(lp->wq); break; } } /* case SL_IOC_MAGIC: *//* can't control these thru SGP */ /* case SDT_IOC_MAGIC: *//* can't control these thru SGP */ /* case SDL_IOC_MAGIC: *//* can't control these thru SGP */ /* case DEV_IOC_MAGIC: *//* can't control these thru SGP */ } if (err) { mp->b_datap->db_type = M_IOCNAK; iocp->ioc_error = err; iocp->ioc_rval = -1; } else { mp->b_datap->db_type = M_IOCACK; iocp->ioc_error = 0; iocp->ioc_rval = 0; } qreply(q, mp); return (1); } /* * ------------------------------------------------------------------------- * * M_PROTO Handling * * ------------------------------------------------------------------------- */ static int sgp_u_w_proto(queue_t * q, mblk_t * mp) { switch (*((long *) mp->b_rptr)) { case LM_AS_ADD_REQ: return lm_as_add_req(q, mp); case LM_AS_DEL_REQ: return lm_as_del_req(q, mp); case LM_PROC_ADD_REQ: return lm_proc_add_req(q, mp); case LM_PROC_DEL_REQ: return lm_proc_del_req(q, mp); case LM_LINK_ADD_REQ: return lm_link_add_req(q, mp); case LM_LINK_DEL_REQ: return lm_link_del_req(q, mp); case LM_ROUTE_ADD_REQ: return lm_route_add_req(q, mp); case LM_ROUTE_DEL_REQ: return lm_route_del_req(q, mp); case LM_REG_RES: return lm_reg_res(q, mp); } return (-EOPNOTSUPP); } static int sgp_l_r_proto(queue_t * q, mblk_t * mp) { switch (*((long *) mp->b_rptr)) { case N_DATA_IND: return n_data_ind(q, mp); case N_EXDATA_IND: return n_exdata_ind(q, mp); case N_DATACK_IND: return n_datack_ind(q, mp); case N_CONN_IND: case N_CONN_CON: case N_DISCON_IND: case N_INFO_ACK: case N_BIND_ACK: case N_ERROR_ACK: case N_OK_ACK: case N_UNITDATA_IND: case N_UDERROR_IND: case N_RESET_IND: case N_RESET_CON: default: return n_other_ind(q, mp); } } static int sgp_u_r_proto(queue_t * q, mblk_t * mp) { return (5); } static int sgp_l_w_proto(queue_t * q, mblk_t * mp) { return (5); } /* * ------------------------------------------------------------------------- * * M_PCPROTO Handling * * ------------------------------------------------------------------------- */ static int sgp_u_w_pcproto(queue_t * q, mblk_t * mp) { return sgp_u_w_proto(q, mp); } static int sgp_l_r_pcproto(queue_t * q, mblk_t * mp) { return sgp_l_r_proto(q, mp); } static int sgp_u_r_pcproto(queue_t * q, mblk_t * mp) { return (4); } static int sgp_l_w_pcproto(queue_t * q, mblk_t * mp) { return (4); } /* * ------------------------------------------------------------------------- * * M_DATA Handling * * ------------------------------------------------------------------------- */ static int sgp_u_w_data(queue_t * q, mblk_t * dp) { (void) q; (void) dp; ptrace(("SGP received M_DATA on upper WR(q)\n")); return (-EOPNOTSUPP); } /* * Any M_DATA read by the lower N provider must be converted to M_PROTO to * avoid interfering with the internal interface. */ static int sgp_l_r_data(queue_t * q, mblk_t * dp) { int err; mblk_t *mp; N_data_ind_t *p; if ((mp = allocb(sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->PRIM_type = N_DATA_IND; p->DATA_xfer_flags = 0; mp->b_cont = dp; switch ((err = n_data_ind(q, mp))) { case 0: freeb(mp); return (0); case 1: break; case 2: freeb(mp); break; case 3: if (!q->q_next) { qreply(q, mp); break; } case 4: if (q->q_next) { putnext(q, mp); break; } case 5: if (canputnext(q)) { putnext(q, mp); break; } default: freeb(mp); return (err); } return (1); } return (-ENOBUFS); } static int sgp_u_r_data(queue_t * q, mblk_t * mp) { return (5); } static int sgp_l_w_data(queue_t * q, mblk_t * mp) { return (5); } /* * ------------------------------------------------------------------------- * * M_CTL Handling * * ------------------------------------------------------------------------- */ static int sgp_u_w_ctl(queue_t * q, mblk_t * mp) { (void) q; (void) mp; rare(); return (-EOPNOTSUPP); } static int sgp_l_r_ctl(queue_t * q, mblk_t * mp) { (void) q; (void) mp; rare(); return (-EOPNOTSUPP); } static int sgp_u_r_ctl(queue_t * q, mblk_t * mp) { return sgp_u_r_data(q, mp); } static int sgp_l_w_ctl(queue_t * q, mblk_t * mp) { return sgp_l_w_data(q, mp); } /* * ------------------------------------------------------------------------- * * M_HANGUP Handling * * ------------------------------------------------------------------------- */ static int sgp_u_w_hangup(queue_t * q, mblk_t * mp) { /* * We need to treat this as a close and do all the things that we * would do before deallocating the structure (except deallocating * the structure.) */ fixme(("Stuff to do here...\n")); return (-EFAULT); } static int sgp_l_r_hangup(queue_t * q, mblk_t * mp) { /* * We need to propagate the hangup to all users of this provider. */ fixme(("Stuff to do here...\n")); return (-EFAULT); } static int sgp_u_r_hangup(queue_t * q, mblk_t * mp) { return (4); } static int sgp_l_w_hangup(queue_t * q, mblk_t * mp) { /* * This is the same effect as a close on a linked stream. We need to * do all the things that would otherwise be done if the stream was * closed. The other thing that we could do is write drivers to * accept M_HANGUP written and treat them as a close (without * deallocation of the private structure). */ fixme(("Stuff to do here...\n")); return (4); } /* * ------------------------------------------------------------------------- * * M_ERROR Handling * * ------------------------------------------------------------------------- */ static int sgp_l_r_error(queue_t * q, mblk_t * mp) { /* * The provider stream has errored out, so we need to propagate the * error to all users of this stream. */ fixme(("Stuff to do here...\n")); return (-EFAULT); } static int sgp_u_r_error(queue_t * q, mblk_t * mp) { return (4); } /* * ------------------------------------------------------------------------- * * M_FLUSH Handling * * ------------------------------------------------------------------------- */ static int sgp_m_flush(queue_t * q, mblk_t * mp, const uint8_t mflag, const uint8_t oflag); { if (mp->b_rptr[0] & mflag) { if (mp->b_rptr[0] & FLUSHBAND) flushband(q, mp->b_rptr[1], FLUSHALL); else flushq(q, FLUSHALL); if (q->q_next) { putnext(q, mp); return (1); } mp->b_rptr[0] &= ~FLUSHW; } if (mp->b_rptr[0] & oflag && !(mp->b_flag & MSGNOLOOP)) { queue_t *oq = q->q_other; if (mp->b_rptr[0] & FLUSHBAND) flushband(oq, mp->b_rptr[1], FLUSHALL); else flushq(oq, FLUSHALL); mp->b_flag |= MSGNOLOOP; qreply(q, mp); return (1); } return (0); } static int sgp_u_w_flush(queue_t * q, mblk_t * mp) { return sgp_m_flush(q, mp, FLUSHW, FLUSHR); } static int sgp_l_r_flush(queue_t * q, mblk_t * mp) { return sgp_m_flush(q, mp, FLUSHR, FLUSHW); } static int sgp_u_r_flush(queue_t * q, mblk_t * mp) { return sgp_m_flush(q, mp, FLUSHR, FLUSHW); } static int sgp_l_w_flush(queue_t * q, mblk_t * mp) { return sgp_m_flush(q, mp, FLUSHW, FLUSHR); } /* * ------------------------------------------------------------------------- * * Other message Handling * * ------------------------------------------------------------------------- */ static int sgp_u_w_other(queue_t * q, mblk_t * mp) { (void) q; (void) mp; ptrace(("Received unexpected message %ld on upper WR(q)\n", *((long *) mp->b_rptr))); return (-EOPNOTSUPP); } static int sgp_l_r_other(queue_t * q, mblk_t * mp) { (void) q; (void) mp; ptrace(("Received unexpected message %ld on lower RD(q)\n", *((long *) mp->b_rptr))); return (-EOPNOTSUPP); } static int sgp_u_r_other(queue_t * q, mblk_t * mp) { if (mp->b_datap->db_type >= QPCTL || canputnext(q)) return (4); return (-EBUSY); } static int sgp_l_w_other(queue_t * q, mblk_t * mp) { if (mp->b_datap->db_type >= QPCTL || canputnext(q)) return (4); return (-EBUSY); } /* * ========================================================================= * * STREAMS PUTQ and SRVQ routines * * ========================================================================= */ /* * UA PUTQ * ------------------------------------------------------------------------- */ static int ua_putq(queue_t * q, mblk_t * mp, int (*proc) (queue_t *, mblk_t *)) { int rtn; ensure(q, return (-EFAULT)); ensure(mp, return (-EFAULT)); if (mp->b_datap->db_type < QPCTL && q->q_count) { seldom(); putq(q, mp); return (0); } switch ((rtn = (*proc) (q, mp))) { case 0: freemsg(mp); case 1: break; case 2: freeb(mp); break; case 3: if (!q->q_next) { qreply(q, mp); break; } case 4: if (q->q_next) { putnext(q, mp); break; } rtn = -EOPNOTSUPP; default: ptrace(("Error (dropping) %d\n", rtn)); freemsg(mp); return (rtn); case 5: if (canputnext(q)) { putnext(q, mp); break; } case -ENOBUFS: /* caller must schedule bufcall */ case -EBUSY: /* caller must have failed canput */ case -EAGAIN: /* caller must re-enable queue */ case -ENOMEM: /* caller must re-enable queue */ putq(q, mp); break; } return (0); } /* * UA SRVQ * ------------------------------------------------------------------------- */ static int ua_srvq(queue_t * q, int (*proc) (queue_t *, mblk_t *)) { int rtn; mblk_t *mp; while ((mp = getq(q))) { switch ((rtn = (*proc) (q, mp))) { case 0: freemsg(mp); case 1: continue; case 2: freeb(mp); continue; case 3: if (!q->q_next) { qreply(q, mp); continue; } case 4: if (q->q_next) { putnext(q, mp); continue; } rtn = -EOPNOTSUPP; default: ptrace(("Error (dropping) %d\n", rtn)); freemsg(mp); continue; case 5: if (canputnext(q)) { putnext(q, mp); continue; } case -ENOBUFS: /* caller must schedule bufcall */ case -EBUSY: /* caller must have failed canput */ case -EAGAIN: /* caller must re-enable queue */ case -ENOMEM: /* caller must re-enable queue */ if (mp->b_datap->db_type < QPCTL) { putb(q, mp); return (rtn); } ptrace(("Error (dropping) %d\n", rtn)); freemsg(mp); continue; } } return (0); } /* * UPPER WR and RD PUT and SRV * ----------------------------------- */ static int sgp_u_w_prim(queue_t * q, mblk_t * mp) { switch (mp->b_datap->db_type) { case M_DATA: return sgp_u_w_data(q, mp); case M_PROTO: return sgp_u_w_proto(q, mp); case M_PCPROTO: return sgp_u_w_pcproto(q, mp); case M_IOCTL: return sgp_u_w_ioctl(q, mp); case M_IOCDATA: return sgp_u_w_iocdata(q, mp); case M_HANGUP: return sgp_u_w_hangup(q, mp); case M_FLUSH: return sgp_u_w_flush(q, mp); default: return sgp_u_w_other(q, mp); } } static INT sgp_u_wput(queue_t * q, mblk_t * mp) { return ((INT) ua_putq(q, mp, &sgp_u_w_prim)); } static INT sgp_u_wsrv(queue_t * q) { return ((INT) ua_srvq(q, &sgp_u_w_prim)); } static int sgp_u_r_prim(queue_t * q, mblk_t * mp) { switch (mp->b_datap->db_type) { case M_DATA: return sgp_u_r_data(q, mp); case M_PROTO: return sgp_u_r_proto(q, mp); case M_PCPROTO: return sgp_u_r_pcproto(q, mp); case M_CTL: return sgp_u_r_ctl(q, mp); case M_HANGUP: return sgp_u_r_hangup(q, mp); case M_ERROR: return sgp_u_r_error(q, mp); case M_FLUSH: return sgp_u_r_flush(q, mp); default: return sgp_u_r_other(q, mp); } } static INT sgp_u_rput(queue_t * q, mblk_t * mp) { return ((INT) ua_putq(q, mp, &sgp_u_r_prim)); } static INT sgp_u_rsrv(queue_t * q) { return ((INT) ua_srvq(q, &sgp_u_r_prim)); } /* * LOWER WR and RD PUT and SRV * ----------------------------------- */ static int sgp_l_w_prim(queue_t * q, mblk_t * mp) { switch (mp->b_datap->db_type) { case M_DATA: return sgp_l_w_data(q, mp); case M_PROTO: return sgp_l_w_proto(q, mp); case M_PCPROTO: return sgp_l_w_pcproto(q, mp); case M_HANGUP: return sgp_l_w_hangup(q, mp); case M_FLUSH: return sgp_l_w_flush(q, mp); default: return sgp_l_w_other(q, mp); } } static INT sgp_l_wput(queue_t * q, mblk_t * mp) { return ((INT) ua_putq(q, mp, &sgp_l_w_prim)); } static INT sgp_l_wsrv(queue_t * q) { return ((INT) ua_srvq(q, &sgp_l_w_prim)); } static int sgp_l_r_prim(queue_t * q, mblk_t * mp) { switch (mp->b_datap->db_type) { case M_DATA: return sgp_l_r_data(q, mp); case M_PROTO: return sgp_l_r_proto(q, mp); case M_PCPROTO: return sgp_l_r_pcproto(q, mp); case M_CTL: return sgp_l_r_ctl(q, mp); case M_HANGUP: return sgp_l_r_hangup(q, mp); case M_ERROR: return sgp_l_r_error(q, mp); case M_FLUSH: return sgp_l_r_flush(q, mp); default: return sgp_l_r_other(q, mp); } } static INT sgp_l_rput(queue_t * q, mblk_t * mp) { return ((INT) ua_putq(q, mp, &sgp_l_r_prim)); } static INT sgp_l_rsrv(queue_t * q) { return ((INT) ua_srvq(q, &sgp_l_r_prim)); } /* * ========================================================================= * * OPEN and CLOSE * * ========================================================================= */ static ua_t *sgp_opens_list = NULL; static int sgp_open(queue_t * q, dev_t * devp, int flag, int sflag, cred_t * crp) { int cmajor = getmajor(*devp); int cminor = getminor(*devp); dp_t *dp, **dpp; if (q->q_ptr != NULL) return (0); /* already open */ if (sflag == MODOPEN || WR(q)->q_next) return (EIO); /* can't open as module */ if (!cminor) sflag = CLONEOPEN; if (sflag == CLONEOPEN) cminor = 1; dpp = &sgp_opens_list; for (; *dpp && getmajor((*dpp)->id.dev) < cmajor; dpp = &(*dpp)->next); for (; *dpp && cminor <= ASP_NMINOR; dpp = &(*dpp)->next) { ushort dminor = getminor((*dpp)->id.dev); if (cminor < dminor) break; if (cminor == dminor) { if (sflag == CLONEOPEN) { cminor++; continue; } return (EIO); /* requested device in use */ } } if (cminor > ASP_NMINOR) return (ENXIO); *devp = makedevice(cmajor, minor); if (!(dp = kmem_cache_alloc(ua_pp_cachep, SLAB_ATOMIC))) return (ENOMEM); bzero(dp, sizeof(ua_t)); if ((dp->next = *dpp)) dp->next->prev = &dp->next; dp->prev = dpp; *dpp = dp; dp->id.dev = *devp; dp->rq = RD(q); dp->wq = WR(q); dp->mq = RD(q); dp->rq->q_ptr = dp->wq->q_ptr = dp; return (0); } static int sgp_close(queue_t * q, int flag, cred_t * crp) { dp_t *dp = (dp_t *) q->q_ptr; if ((*(dp->prev) = dp->next)) dp->next->prev = dp->prev; dp->prev = NULL; dp->next = NULL; if (dp->bid) unbufcall(dp->bid); dp->rq->q_ptr = NULL; dp->wq->q_ptr = NULL; kmem_cache_free(ua_pp_cachep, dp); return (0); } /* * ========================================================================= * * LiS Module Initialization * * ========================================================================= */ int sgp_init(void) { int cmajor; if (!sgp_u_minfo.mi_idnum) { if ((cmajor = lis_regsiter_strdev(ASP_CMAJOR, &sgp_info, ASP_NMINOR, sgp_u_minfo.mi_idname)) < 0) { sgp_u_minfo.mi_idnum = 0; rare(); cnm_err(CE_NOTE, "sgp: couldn't register driver\n"); return; } sgp_u_minfo.mi_idnum = cmajor; } return (0); } void sgp_terminate(void) { if (sgp_u_minfo.mi_idnum) { if ((sgp_u_minfo.mi_idnum = lis_unregister_strdev(sgp_u_minfo.mi_idnum))) { sgp_u_minfo.mi_idnum = 0; rare(); cmn_err(CE_WARN, "sgp: couldn't unregister driver!\n"); } } } /* * ========================================================================= * * Kernel Module Initialization * * ========================================================================= */ int init_module(void) { int err; sgp_init(); return (0); } void cleanup_module(void) { sgp_terminate(); return; }
|
|||||||||||||||||||||||||||
OpenSS7 SS7 for the Common Man |
Home | Overview | Status | News | Documentation | Resources | About | ||||||||||||||||||||
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |