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/slsi/sls.c#ident "@(#) $RCSfile: sls.c,v $ $Name: $($Revision: 0.8.2.4 $) $Date: 2003/04/14 12:13:27 $" static char const ident[] = "$RCSfile: sls.c,v $ $Name: $($Revision: 0.8.2.4 $) $Date: 2003/04/14 12:13:27 $"; /* * This is an SLS (Signalling Link Set) loadable module which provides all of * the capabilities of the SLSI. It can be used by drivers in two fashions: * * 1) Drivers can provide a set of missing functions by registering with the * module using the ls_register_driver. This relieves much of the * STREAMS burden from the driver implementation and permits the driver * to be more portable across the Linux, STREAMS, and BSD implementation * of the OpenSS7 stack. * * 2) Driver which implement the OpenSS7 SLI can be linked under this * multiplexor to form an SLSI driver implementation. * * Both fashions permit SS7 Level 2 and 3 compliant state machines to be * tested once, but used by many drivers. */ #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 "../lock.h" #include "../debug.h" #include "../bufq.h" #include <ss7/lmi.h> #include <ss7/lmi_ioctl.h> #include <ss7/devi.h> #include <ss7/devi_ioctl.h> #include <ss7/sdli.h> #include <ss7/sdli_ioctl.h> #include <ss7/sdti.h> #include <ss7/sdti_ioctl.h> #include <ss7/sli.h> #include <ss7/sli_ioctl.h> #include <ss7/slsi.h> #include <ss7/slsi_ioctl.h> #include "../lmi/lm.h" #include "../devi/dev.h" #include "../sdli/sdl.h" #include "../sdti/sdt.h" #include "../sli/sl.h" #include "../slsi/sls.h" #include "sls_codec.h" /* message parsing and building */ #define LS_DESCRIP "SS7/SLS: (Signalling Link Set) STREAMS DRIVER." #define LS_COPYRIGHT "Copyright (c) 1997-2002 OpenSS7 Corporation. All Rights Reserved." #define LS_DEVICES "Supports OpenSS7 SLS drivers." #define LS_CONTACT "Brian Bidulock <bidulock@openss7.org>" #define LS_LICENSE "GPL" #define LS_BANNER LS_DESCRIP "\n" \ LS_COPYRIGHT "\n" \ LS_DEVICES "\n" \ LS_CONTACT "\n" #ifdef MODULE MODULE_AUTHOR(LS_CONTACT); MODULE_DESCRIPTION(LS_DESCRIP); MODULE_SUPPORTED_DEVICE(LS_DEVICES); #ifdef MODULE_LICENSE MODULE_LICENSE(LS_LICENSE); #endif #define MODULE_STATIC static #else #define MOD_INC_USE_COUNT #define MOD_DEC_USE_COUNT #define MODULE_STATIC #endif #ifdef LS_DEBUG static int ls_debug = LS_DEBUG; #else static int ls_debug = 2; #endif #define DEBUG_LEVEL ls_debug #ifndef LS_CMAJOR #define LS_CMAJOR 249 #endif #define LS_NMINOR 255 /* * ======================================================================= * * STREAMS Definitions * * ======================================================================= */ static struct module_info ls_minfo = { 0, /* Module ID number */ "ls", /* Module name */ 5, /* Min packet size accepted */ 272, /* Max packet size accepted */ 8 * 272, /* Hi water mark */ 1 * 272 /* Lo water mark */ }; static void ls_rput(queue_t *, mblk_t *); static void ls_rsrv(queue_t *); static int ls_open(queue_t *, dev_t *, int, int, cred_t *); static int ls_close(queue_t *, int, cred_t *); static struct qinit ls_rinit = { ls_rput, /* Read put (msg from below) */ ls_rsrv, /* Read queue service */ ls_open, /* Each open */ ls_close, /* Last close */ NULL, /* Admin (not used) */ &ls_minfo, /* Information */ NULL /* Statistics */ }; static void ls_wput(queue_t *, mblk_t *); static void ls_wsrv(queue_t *); static struct qinit ls_winit = { ls_wput, /* Write put (msg from above) */ ls_wsrv, /* Write queue service */ NULL, /* Each open */ NULL, /* Last close */ NULL, /* Admin (not used) */ &ls_minfo, /* Information */ NULL /* Statistics */ }; static struct module_info lk_minfo = { 0, /* Module ID number */ "ls-lower", /* Module name */ 5, /* Min packet size accepted */ 272, /* Max packet size accepted */ 8 * 272, /* Hi water mark */ 1 * 272 /* Lo water mark */ }; static void lk_rput(queue_t *, mblk_t *); static void lk_rsrv(queue_t *); static struct qinit lk_rinit = { lk_rput, /* Write put (msg from above) */ lk_rsrv, /* Write queue service */ NULL, /* Each open */ NULL, /* Last close */ NULL, /* Admin (not used) */ &lk_minfo, /* Information */ NULL /* Statistics */ }; static void lk_wput(queue_t *, mblk_t *); static void lk_wsrv(queue_t *); static struct qinit lk_winit = { lk_wput, /* Write put (msg from above) */ lk_wsrv, /* Write queue service */ NULL, /* Each open */ NULL, /* Last close */ NULL, /* Admin (not used) */ &lk_minfo, /* Information */ NULL /* Statistics */ }; #ifdef MODULE static #endif struct streamtab ls_info = { &ls_rinit, /* Upper read queue */ &ls_winit, /* Upper write queue */ &lk_rinit, /* Lower read queue */ &lk_winit /* Lower write queue */ }; /* * ======================================================================= * * LMI PROTOCOL CONFIGURATION IOCTLs * * ======================================================================= */ static int ls_iocgoptions(ls_t * ls, int cmd, void *arg) { DTRACE; bcopy(&ls->option, arg, _IOC_SIZE(cmd)); return (0); } static int ls_iocsoptions(ls_t * ls, int cmd, void *arg) { DTRACE; bcopy(arg, &ls->option, _IOC_SIZE(cmd)); return (0); } static int ls_iocgconfig(ls_t * ls, int cmd, void *arg) { DTRACE; bcopy(&ls->config, arg, _IOC_SIZE(cmd)); return (0); } static int ls_iocsconfig(ls_t * ls, int cmd, void *arg) { signed long int *src, *dst, *end; DTRACE; dst = (signed long int *) &ls->config; end = (signed long int *) ((&ls->config) + 1); src = arg; while (dst < end) { if (*src != -1) *dst = *src; dst++; src++; } return (0); } static int ls_iocgstatem(ls_t * ls, int cmd, void *arg) { DTRACE; bcopy(&ls->statem, arg, _IOC_SIZE(cmd)); return (0); } static int ls_iocsstatsp(ls_t * ls, int cmd, void *arg) { DTRACE; (void) arg; return EOPNOTSUPP; } static int ls_iocgstatsp(ls_t * ls, int cmd, void *arg) { DTRACE; (void) arg; return EOPNOTSUPP; } static int ls_ioccstats(ls_t * ls, int cmd, void *arg) { DTRACE; (void) arg; bzero(&ls->stats, _IOC_SIZE(cmd)); return (0); } static int ls_iocgstats(ls_t * ls, int cmd, void *arg) { DTRACE; bcopy(&ls->stats, arg, _IOC_SIZE(cmd)); return (0); } static int ls_iocsnotify(ls_t * ls, int cmd, void *arg) { caddr_t dst, src, end; DTRACE; src = arg; dst = (caddr_t) & ls->notify; end = (caddr_t) ((&ls->notify) + 1); while (dst < end) *dst++ |= *src++; return (0); } static int ls_ioccnotify(ls_t * ls, int cmd, void *arg) { caddr_t dst, src, end; DTRACE; src = arg; dst = (caddr_t) & ls->notify; end = (caddr_t) ((&ls->notify) + 1); while (dst < end) *dst++ &= ~*src++; return (0); } static int ls_iocgnotify(ls_t * ls, int cmd, void *arg) { DTRACE; bcopy(&ls->notify, arg, _IOC_SIZE(cmd)); return (0); } static int (*ls_ioc_lmiops[]) (ls_t *, int, void *) = { ls_iocgoptions, /* LS_IOCGOPTIONS */ ls_iocsoptions, /* LS_IOCSOPTIONS */ ls_iocgconfig, /* LS_IOCGCONFIG */ ls_iocsconfig, /* LS_IOCSCONFIG */ NULL, /* LS_IOCTCONFIG */ NULL, /* LS_IOCCCONFIG */ ls_iocgstatem, /* LS_IOCGSTATEM */ NULL, /* LS_IOCCMRESET */ ls_iocgstatsp, /* LS_IOCGSTATSP */ ls_iocsstatsp, /* LS_IOCSSTATSP */ ls_iocgstats, /* LS_IOCGSTATS */ ls_ioccstats, /* LS_IOCCSTATS */ ls_iocgnotify, /* LS_IOCGNOTIFY */ ls_iocsnotify, /* LS_IOCSNOTIFY */ ls_ioccnotify /* LS_IOCCNOTIFY */ }; /* * ======================================================================= * * LS->RT Service Primitives (M_CTL, M_PROTO, M_PCPROTO * * ======================================================================= */ static inline void ls_uprim_msg(ls_t * ls, int type, int prim, mblk_t * mp) { mp->b_datap->db_type = type; *((ls_long *) mp->b_rptr) = prim; ls_rput(ls->rq, mp); } static inline void ls_uprim_link(ls_t * ls, int type, int prim, int slc) { mblk_t *mp; if ((mp = allocb(sizeof(ls_link_t), BPRI_HI))) { ls_link_t *p = (ls_link_t *) mp->b_wptr; mp->b_wptr += sizeof(ls_link_t); mp->b_datap->db_type = type; p->primitive = prim; p->lpc = ls->config.lpc; p->apc = ls->config.apc; p->slc = slc; ls_rput(ls->rq, mp); } } static inline void ls_uprim(ls_t * ls, int type, int prim) { mblk_t *mp; if ((mp = allocb(sizeof(ls_long), BPRI_HI))) { mp->b_datap->db_type = type; *((ls_long *) mp->b_wptr)++ = prim; ls_rput(ls->rq, mp); } } static inline void ls_uprim_cong(ls_t * ls, int type, int prim) { mblk_t *mp; if ((mp = allocb(sizeof(ls_congestion_t), BPRI_HI))) { ls_congestion_t *p = (ls_congestion_t *) mp->b_rptr; mp->b_wptr += sizeof(ls_congestion_t); mp->b_datap->db_type = type; p->primitive = prim; p->cong_status = ls->statem.cong_status; p->disc_status = ls->statem.disc_status; ls_rput(ls->rq, mp); } } static void ls_rt_message_for_routing(ls_t * ls, mblk_t * mp) { ls_uprim_msg(ls, M_PROTO, LS_MESSAGE_FOR_ROUTING_IND, mp); } static void ls_rt_message_for_discrimination(ls_t * ls, mblk_t * mp) { ls_uprim_msg(ls, M_PROTO, LS_MESSAGE_FOR_DISCRIMINATION_IND, mp); } static void ls_rt_link_inhibited(ls_t * ls, int slc) { ls_uprim_link(ls, M_PROTO, LS_LINK_INHIBITED_IND, slc); } static void ls_rt_link_inhibit_denied(ls_t * ls, int slc) { ls_uprim_link(ls, M_PROTO, LS_LINK_INHIBIT_DENIED_IND, slc); } static void ls_rt_link_inhibit_failed(ls_t * ls, int slc) { ls_uprim_link(ls, M_PROTO, LS_LINK_INHIBIT_FAILED_IND, slc); } static void ls_rt_link_uninhibited(ls_t * ls, int slc) { ls_uprim_link(ls, M_PROTO, LS_LINK_UNINHIBITED_IND, slc); } static void ls_rt_link_uninhibit_failed(ls_t * ls, int slc) { ls_uprim_link(ls, M_PROTO, LS_LINK_UNINHIBIT_FAILED_IND, slc); } static void ls_rt_force_uninhibit_failed(ls_t * ls) { ls_uprim(ls, M_PROTO, LS_FORCE_UNINHIBIT_FAILED_IND); } static void ls_rt_available(ls_t * ls) { ls_uprim(ls, M_PROTO, LS_AVAILABLE_IND); } static void ls_rt_unavailable(ls_t * ls) { ls_uprim(ls, M_PROTO, LS_UNAVAILABLE_IND); } static void ls_rt_retrieved_message(ls_t * ls, mblk_t * mp) { ls_uprim_msg(ls, M_PROTO, LS_RETRIEVED_MESSAGE_IND, mp); } static void ls_rt_retrieval_complete(ls_t * ls) { ls_uprim(ls, M_PROTO, LS_RETRIEVAL_COMPLETE_IND); } static void ls_rt_congested(ls_t * ls, int cong, int disc) { ls->statem.cong_status = cong; ls->statem.disc_status = disc; ls_uprim_cong(ls, M_PCPROTO, LS_CONGESTED_IND); } static void ls_rt_congestion_ceased(ls_t * ls, int cong, int disc) { ls->statem.cong_status = cong; ls->statem.disc_status = disc; ls_uprim_cong(ls, M_PCPROTO, LS_CONGESTION_CEASED_IND); } static void ls_rt_link_in_service_at_level_2(ls_t * ls) { ls_uprim(ls, M_PROTO, LS_LINK_IN_SERVICE_AT_LEVEL_2_IND); } static ls_ucalls_t ls_mux_ucalls = { ls_rt_message_for_routing, /* ls_msg_for_routing */ ls_rt_message_for_discrimination, /* ls_msg_for_discrim */ ls_rt_link_inhibited, /* ls_inhibited */ ls_rt_link_inhibit_denied, /* ls_inhibit_denied */ ls_rt_link_inhibit_failed, /* ls_inhibit_failed */ ls_rt_link_uninhibited, /* ls_uninhibited */ ls_rt_link_uninhibit_failed, /* ls_uninhibit_failed */ ls_rt_force_uninhibit_failed, /* ls_force_unihibit_failed */ ls_rt_available, /* ls_available */ ls_rt_unavailable, /* ls_unavailable */ ls_rt_retrieved_message, /* ls_retrieved_message */ ls_rt_retrieval_complete, /* ls_retrieval_complete */ ls_rt_congested, /* ls_congested */ ls_rt_congestion_ceased, /* ls_congestion_ceased */ ls_rt_link_in_service_at_level_2 /* ls_in_service_at_l2 */ }; /* * ========================================================================= * * LK->SL Service Primitives (M_CTL, M_PROTO, M_PCPROTO) * * ========================================================================= */ static inline void lk_dprim_msg(lk_t * lk, int type, int prim, mblk_t * mp) { if (mp->b_datap->db_type != M_DATA) { *((sl_long *) mp->b_rptr) = SL_PDU_REQ; mp->b_datap->db_type = type; } lk_wput(lk->wq, mp); } static inline void lk_dprim(lk_t * lk, int type, int prim) { mblk_t *mp; if ((mp = allocb(sizeof(sl_long), BPRI_HI))) { mp->b_datap->db_type = type; *((sl_long *) mp->b_wptr)++ = prim; lk_wput(lk->wq, mp); } } static inline void lk_dprim_arg(lk_t * lk, int type, int prim, int arg) { mblk_t *mp; if ((mp = allocb(2 * sizeof(sl_ulong), BPRI_HI))) { mp->b_datap->db_type = type; *((sl_long *) mp->b_wptr)++ = prim; *((sl_ulong *) mp->b_wptr)++ = arg; lk_wput(lk->wq, mp); } } static void lk_sl_pdu(lk_t * lk, mblk_t * mp) { lk_dprim_msg(lk, M_PROTO, SL_PDU_REQ, mp); } static void lk_sl_emergency(lk_t * lk) { lk_dprim(lk, M_PCPROTO, SL_EMERGENCY_REQ); } static void lk_sl_emergency_ceases(lk_t * lk) { lk_dprim(lk, M_PCPROTO, SL_EMERGENCY_CEASES_REQ); } static void lk_sl_start(lk_t * lk) { lk_dprim(lk, M_PROTO, SL_START_REQ); } static void lk_sl_stop(lk_t * lk) { lk_dprim(lk, M_PCPROTO, SL_STOP_REQ); } static void lk_sl_retrieve_bsnt(lk_t * lk) { lk_dprim(lk, M_PCPROTO, SL_RETRIEVE_BSNT_REQ); } static void lk_sl_retrieval_request_and_fsnc(lk_t * lk, int fsnc) { lk_dprim_arg(lk, M_PROTO, SL_RETRIEVAL_REQUEST_AND_FSNC_REQ, fsnc); } static void lk_sl_resume(lk_t * lk) { lk_dprim(lk, M_PCPROTO, SL_RESUME_REQ); } static void lk_sl_clear_buffers(lk_t * lk) { lk_dprim(lk, M_PCPROTO, SL_CLEAR_BUFFERS_REQ); } static void lk_sl_clear_rtb(lk_t * lk) { lk_dprim(lk, M_PCPROTO, SL_CLEAR_RTB_REQ); } static void lk_sl_local_processor_outage(lk_t * lk) { lk_dprim(lk, M_PCPROTO, SL_LOCAL_PROCESSOR_OUTAGE_REQ); } static void lk_sl_congestion_discard(lk_t * lk) { lk_dprim(lk, M_PCPROTO, SL_CONGESTION_DISCARD_REQ); } static void lk_sl_congestion_accept(lk_t * lk) { lk_dprim(lk, M_PCPROTO, SL_CONGESTION_ACCEPT_REQ); } static void lk_sl_no_congestion(lk_t * lk) { lk_dprim(lk, M_PCPROTO, SL_NO_CONGESTION_REQ); } static void lk_sl_power_on(lk_t * lk) { lk_dprim(lk, M_PROTO, SL_POWER_ON_REQ); } /* * ======================================================================= * * PROTOCOL STATE MACHINES * * ======================================================================= */ #include "sls_sm.h" /* link set state machines */ /* * ======================================================================= * * LS->LK Service Calls (M_CTL, M_PROTO, M_PCPROTO * * ======================================================================= */ static ls_mcalls_t ls_mux_dcalls = { ls_message_from_routing, /* ls_msg_from_routing */ ls_message_for_distribution, /* ls_msg_for_dist */ ls_message_for_rerouting, /* ls_msg_for_reroute */ ls_link_activate, /* ls_lk_activate */ ls_link_deactivate, /* ls_lk_deactivate */ ls_link_inhibit, /* ls_lk_inhibit */ ls_link_uninhibit, /* ls_lk_uninhibit */ ls_activate, /* ls_activate */ ls_deactivate, /* ls_deactivate */ ls_inhibit, /* ls_inhibit */ ls_uninhibit, /* ls_uninhibit */ ls_force_uninhibit, /* ls_force_unihibit */ ls_routing_outage, /* ls_routing_outage */ ls_routing_recovered, /* ls_routing_recovered */ ls_critical, /* ls_critical */ ls_noncritical, /* ls_noncritical */ ls_emergency, /* ls_emerg */ ls_emergency_ceases, /* ls_emerg_ceases */ ls_traffic_starts, /* ls_traffic */ ls_traffic_ends, /* ls_no_traffic */ ls_adjacent_sp_inaccessible, /* ls_adj_inaccessible */ ls_adjacent_sp_accessible /* ls_adj_accessible */ }; /* * ======================================================================= * * LS<-RT Service Primitives (M_CTL, M_PROTO, M_PCPROTO) * * ======================================================================= */ static void ls_message_for_routing_req(ls_t * ls, mblk_t * mp) { ls->dcalls->ls_msg_from_routing(ls, mp); } static void ls_message_for_distribution_req(ls_t * ls, mblk_t * mp) { ls->dcalls->ls_msg_for_dist(ls, mp); } static void ls_message_for_rerouting_req(ls_t * ls, mblk_t * mp) { ls->dcalls->ls_msg_for_reroute(ls, mp); } static void ls_link_activate_req(ls_t * ls, mblk_t * mp) { ls_link_t *p = (ls_link_t *) mp->b_rptr; int slc = p->slc; freemsg(mp); ls->dcalls->ls_lk_activate(ls, slc); } static void ls_link_deactivate_req(ls_t * ls, mblk_t * mp) { ls_link_t *p = (ls_link_t *) mp->b_rptr; int slc = p->slc; freemsg(mp); ls->dcalls->ls_lk_deactivate(ls, slc); } static void ls_link_inhibit_req(ls_t * ls, mblk_t * mp) { ls_link_t *p = (ls_link_t *) mp->b_rptr; int slc = p->slc; freemsg(mp); ls->dcalls->ls_lk_inhibit(ls, slc); } static void ls_link_uninhibit_req(ls_t * ls, mblk_t * mp) { ls_link_t *p = (ls_link_t *) mp->b_rptr; int slc = p->slc; freemsg(mp); ls->dcalls->ls_lk_uninhibit(ls, slc); } static void ls_activate_req(ls_t * ls, mblk_t * mp) { freemsg(mp); ls->dcalls->ls_activate(ls); } static void ls_deactivate_req(ls_t * ls, mblk_t * mp) { freemsg(mp); ls->dcalls->ls_deactivate(ls); } static void ls_inhibit_req(ls_t * ls, mblk_t * mp) { freemsg(mp); ls->dcalls->ls_inhibit(ls); } static void ls_uninhibit_req(ls_t * ls, mblk_t * mp) { freemsg(mp); ls->dcalls->ls_uninhibit(ls); } static void ls_force_uninhibit_req(ls_t * ls, mblk_t * mp) { freemsg(mp); ls->dcalls->ls_force_uninhibit(ls); } static void ls_routing_outage_req(ls_t * ls, mblk_t * mp) { freemsg(mp); ls->dcalls->ls_routing_outage(ls); } static void ls_routing_recovered_req(ls_t * ls, mblk_t * mp) { freemsg(mp); ls->dcalls->ls_routing_recovered(ls); } static void ls_critical_req(ls_t * ls, mblk_t * mp) { freemsg(mp); ls->dcalls->ls_critical(ls); } static void ls_noncritical_req(ls_t * ls, mblk_t * mp) { freemsg(mp); ls->dcalls->ls_noncritical(ls); } static void ls_emergency_req(ls_t * ls, mblk_t * mp) { freemsg(mp); ls->dcalls->ls_emerg(ls); } static void ls_emergency_ceases_req(ls_t * ls, mblk_t * mp) { freemsg(mp); ls->dcalls->ls_emerg_ceases(ls); } static void ls_traffic_starts_req(ls_t * ls, mblk_t * mp) { freemsg(mp); ls->dcalls->ls_traffic(ls); } static void ls_traffic_ends_req(ls_t * ls, mblk_t * mp) { freemsg(mp); ls->dcalls->ls_no_traffic(ls); } static void ls_adjacent_sp_inaccessible_req(ls_t * ls, mblk_t * mp) { freemsg(mp); ls->dcalls->ls_adj_inaccessible(ls); } static void ls_adjacent_sp_accessible_req(ls_t * ls, mblk_t * mp) { freemsg(mp); ls->dcalls->ls_adj_accessible(ls); } static void (*ls_rt_ops[]) (ls_t *, mblk_t *) = { ls_message_for_routing_req, /* LS_MESSAGE_FOR_ROUTING_REQ */ ls_message_for_distribution_req, /* LS_MESSAGE_FOR_DISTRIBUTION_REQ */ ls_message_for_rerouting_req, /* LS_MESSAGE_FOR_REROUTING_REQ */ ls_link_activate_req, /* LS_LINK_ACTIVATE_REQ */ ls_link_deactivate_req, /* LS_LINK_DEACTIVATE_REQ */ ls_link_inhibit_req, /* LS_LINK_INHIBIT_REQ */ ls_link_uninhibit_req, /* LS_LINK_UNINHIBIT_REQ */ ls_activate_req, /* LS_ACTIVATE_REQ */ ls_deactivate_req, /* LS_DEACTIVATE_REQ */ ls_inhibit_req, /* LS_INHIBIT_REQ */ ls_uninhibit_req, /* LS_UNINHIBIT_REQ */ ls_force_uninhibit_req, /* LS_FORCE_UNIHIBIT_REQ */ ls_routing_outage_req, /* LS_ROUTING_OUTAGE_REQ */ ls_routing_recovered_req, /* LS_ROUTING_RECOVERED_REQ */ ls_critical_req, /* LS_CRITICAL_REQ */ ls_noncritical_req, /* LS_NONCRITICAL_REQ */ ls_emergency_req, /* LS_EMERGENCY_REQ */ ls_emergency_ceases_req, /* LS_EMERGENCY_CEASES_REQ */ ls_traffic_starts_req, /* LS_TRAFFIC_STARTS_REQ */ ls_traffic_ends_req, /* LS_TRAFFIC_ENDS_REQ */ ls_adjacent_sp_inaccessible_req, /* LS_ADJACENT_SP_INACCESSIBLE_REQ */ ls_adjacent_sp_accessible_req /* LS_ADJACENT_SP_ACCESSIBLE_REQ */ }; /* * ======================================================================= * * LK<-SL Service Primitives (M_CTL, M_PROTO, M_PCPROTO) * * ======================================================================= */ static void sl_pdu_ind(lk_t * lk, mblk_t * mp) { sl_pdu(lk, mp); } static void sl_link_congested_ind(lk_t * lk, mblk_t * mp) { sl_prim_t *p = (sl_prim_t *) mp->b_rptr; int cong = p->link_cong_ind.sl_cong_status; int disc = p->link_cong_ind.sl_disc_status; freemsg(mp); sl_link_congested(lk, cong, disc); } static void sl_link_congestion_ceased_ind(lk_t * lk, mblk_t * mp) { sl_prim_t *p = (sl_prim_t *) mp->b_rptr; int cong = p->link_cong_ceased_ind.sl_cong_status; int disc = p->link_cong_ceased_ind.sl_disc_status; freemsg(mp); sl_link_congestion_ceased(lk, cong, disc); } static void sl_retrieved_message_ind(lk_t * lk, mblk_t * mp) { sl_retrieved_message(lk, mp); } static void sl_retrieval_complete_ind(lk_t * lk, mblk_t * mp) { freemsg(mp); sl_retrieval_complete(lk); } static void sl_retrieval_not_possible_ind(lk_t * lk, mblk_t * mp) { freemsg(mp); sl_retrieval_not_possible(lk); } static void sl_rb_cleared_ind(lk_t * lk, mblk_t * mp) { freemsg(mp); sl_rb_cleared(lk); } static void sl_bsnt_ind(lk_t * lk, mblk_t * mp) { sl_prim_t *p = (sl_prim_t *) mp->b_rptr; int bsnt = p->bsnt_ind.sl_bsnt; freemsg(mp); sl_bsnt(lk, bsnt); } static void sl_bsnt_not_retrievable_ind(lk_t * lk, mblk_t * mp) { freemsg(mp); sl_bsnt_not_retrievable(lk); } static void sl_in_service_ind(lk_t * lk, mblk_t * mp) { freemsg(mp); sl_in_service(lk); } static void sl_out_of_service_ind(lk_t * lk, mblk_t * mp) { sl_prim_t *p = (sl_prim_t *) mp->b_rptr; int reason = p->out_of_service_ind.sl_reason; freemsg(mp); sl_out_of_service(lk, reason); } static void sl_remote_processor_outage_ind(lk_t * lk, mblk_t * mp) { freemsg(mp); sl_remote_processor_outage(lk); } static void sl_remote_processor_recovered_ind(lk_t * lk, mblk_t * mp) { freemsg(mp); sl_remote_processor_recovered(lk); } static void sl_rtb_cleared_ind(lk_t * lk, mblk_t * mp) { freemsg(mp); sl_rtb_cleared(lk); } static void (*lk_sl_ops[]) (lk_t *, mblk_t *) = { sl_pdu_ind, /* SL_PDU_IND */ sl_link_congested_ind, /* SL_LINK_CONGESTED_IND */ sl_link_congestion_ceased_ind, /* SL_LINK_CONGESTION_CEASED_IND */ sl_retrieved_message_ind, /* SL_RETRIEVED_MESSAGE_IND */ sl_retrieval_complete_ind, /* SL_RETRIEVAL_COMPLETE_IND */ sl_rb_cleared_ind, /* SL_RB_CLEARED_IND */ sl_bsnt_ind, /* SL_BSNT_IND */ sl_in_service_ind, /* SL_IN_SERVICE_IND */ sl_out_of_service_ind, /* SL_OUT_OF_SERVICE_IND */ sl_remote_processor_outage_ind, /* SL_REMOTE_PROCESSOR_OUTAGE_IND */ sl_remote_processor_recovered_ind, /* SL_REMOTE_PROCESSOR_RECOVERED_IND */ sl_rtb_cleared_ind, /* SL_RTB_CLEARED_IND */ sl_retrieval_not_possible_ind, /* SL_RETRIEVAL_NOT_POSSIBLE_IND */ sl_bsnt_not_retrievable_ind /* SL_BSNT_NOT_RETRIEVABLE_IND */ }; /* * ======================================================================= * * M_IOCTL handling * * ======================================================================= */ static int ls_do_ioctl(lmi_t * ls, int cmd, void *arg) { // lmi_driver_t *drv; int nr = _IOC_NR(cmd); DTRACE; if (_IOC_TYPE(cmd) == LS_IOC_MAGIC) if (LS_IOC_FIRST <= nr && nr <= LS_IOC_LAST) if (ls_ioc_lmiops[nr]) return ls_ioc_lmiops[nr] ((ls_t *) ls, cmd, arg); // if ( (drv = ls->driver) ) // return drv->ops.lmi.ioctl(ls, cmd, arg); /* * NOTE: If we are a multiplexor rather than a driver, we will strip the * first ls_long from the data part of the IOCTL and use that as the * signalling link code. The remainder will be passed to that signalling * link. Thus we can send IOCTLs for the signalling link from above. * Some of the link set IOCTLs must also configure signalling link * parameters. Perhaps all the lower level IOCTLs can be rationalized * into an upper IOCTL. Consider M_CTL for this. */ return -ENXIO; } #ifndef abs #define abs(x) ((x)<0 ? -(x):(x)) #endif static inline int ls_m_ioctl(queue_t * q, mblk_t * mp) { lk_t *lk, **lkp; ls_t *ls = (ls_t *) q->q_ptr; struct iocblk *iocp = (struct iocblk *) mp->b_rptr; void *arg = mp->b_cont ? mp->b_cont->b_rptr : NULL; int cmd = iocp->ioc_cmd, count = iocp->ioc_count; int ret = -EINVAL; struct linkblk *lp = (struct linkblk *) arg; DTRACE; switch (cmd) { case I_LINK: case I_PLINK: /* * NOTE: PLINK can be a bit different an could be rather useful * for SS7. A PLINKED signalling link will never be closed, even * if the configuration daemon crashes, even if the signalling * link set is closed. This permits more permanent SS7 * configuration structures. The ss7d upon restart reopens the * controll channel with root priviledges and can access the * existing configuration. * * NOTE: do a MOD_INC_USE_COUNT when PLINKs are added and a * MOD_DEC_USE_COUNT when they are removed. Otherwise the module * may autoclean. */ if (MINOR(ls->devnum)) { ret = -EPERM; break; } if (!(lk = kmalloc(sizeof(*lk), GFP_KERNEL))) { ret = -ENOMEM; break; } bzero(lk, sizeof(*lk)); lk->next = ls->device; ls->device = lk; lk->module = ls; lk->ucalls = NULL; lk->dcalls = NULL; lk->device = NULL; lk->driver = NULL; lk->muxid = lp->l_index; lk->rq = RD(lp->l_qbot); lk->rq->q_ptr = lk; lk->wq = WR(lp->l_qbot); lk->wq->q_ptr = lk; ret = 0; break; case I_UNLINK: case I_PUNLINK: if (MINOR(ls->devnum)) { ret = -EPERM; break; } for (lkp = &ls->device; *lkp && (*lkp)->muxid != lp->l_index; lkp = &(*lkp)->next); if (!(lk = *lkp)) { ret = -ENXIO; break; } *lkp = lk->next; lk->rq->q_ptr = NULL; lk->wq->q_ptr = NULL; kfree(lk); ret = 0; break; default: if (count >= _IOC_SIZE(cmd)) { ret = ls_do_ioctl((lmi_t *) ls, cmd, arg); } #if 0 /* * FIXME: * * If the IOCTL is destined for the link instead of the linkset, * we should pass the command down to the link. The link can * then attempt to deal with it. We should use the muxid to * determine which link to pass the command to. The muxid should * be the first element in arg. Go through the lower mux list * at ls->device. */ if (abs(ret) == ENXIO) { if (q->q_next) { putnext(q, mp); return (0); } } #endif break; } if (ret == 0) { mp->b_datap->db_type = M_IOCACK; iocp->ioc_error = 0; iocp->ioc_rval = 0; } else { mp->b_datap->db_type = M_IOCNAK; iocp->ioc_error = abs(ret); iocp->ioc_rval = -1; } qreply(q, mp); return (0); } /* * ======================================================================= * * M_PROTO, M_PCPROTO handling * * ======================================================================= */ static inline int ls_m_proto(queue_t * q, mblk_t * mp) { int err = LMI_BADPRIM + EOPNOTSUPP; ls_t *ls = (ls_t *) q->q_ptr; int prim = *((ls_long *) mp->b_rptr); DTRACE; DPRINT(0, ("%s: [%s %d] primitive = %d\n", __FUNCTION__, __FILE__, __LINE__, prim)); if (LS_DSTR_FIRST <= prim && prim <= LS_DSTR_LAST) { (*ls_rt_ops[prim - LS_DSTR_FIRST]) (ls, mp); return (0); } if (q->q_next) { putnext(q, mp); return (0); } if (LMI_DSTR_FIRST <= prim && prim <= LMI_DSTR_LAST) { err = (*lmi_lmi_ops[prim - LMI_DSTR_FIRST]) ((lmi_t *) ls, mp); } return err; } static inline int lk_m_proto(queue_t * q, mblk_t * mp) { int err = LMI_BADPRIM + EOPNOTSUPP; lk_t *lk = (lk_t *) q->q_ptr; int prim = *((sl_long *) mp->b_rptr); DTRACE; DPRINT(0, ("%s: [%s %d] primitive = %d\n", __FUNCTION__, __FILE__, __LINE__, prim)); if (SL_USTR_FIRST <= prim && prim <= SL_USTR_LAST) { (*lk_sl_ops[SL_USTR_LAST - prim]) (lk, mp); return (0); } if (q->q_next) { putnext(q, mp); return (0); } return err; } /* * ======================================================================= * * M_DATA handling * * ======================================================================= */ static inline int lk_m_data(queue_t * q, mblk_t * mp) { lk_t *lk = (lk_t *) q->q_ptr; DTRACE; sl_pdu(lk, mp); return (0); } /* * ======================================================================= * * STREAMS QUEUE PUT and QUEUE SERVICE routines * * ======================================================================= */ /* * ------------------------------------------ * * UPPER QUEUE PUT and QUEUE SERVICE routines * * ------------------------------------------ */ static void ls_wput(queue_t * q, mblk_t * mp) { int err = EOPNOTSUPP; DTRACE; if (q->q_count && mp->b_datap->db_type < QPCTL) { putq(q, mp); return; } switch (mp->b_datap->db_type) { case M_DATA: freemsg(mp); /* don't support raw read/write here */ return; case M_CTL: case M_PROTO: case M_PCPROTO: if ((err = ls_m_proto(q, mp))) break; return; case M_FLUSH: if (*mp->b_rptr & FLUSHW) { flushq(q, FLUSHALL); if (q->q_next) { putnext(q, mp); /* flush all the way down */ return; } *mp->b_rptr &= ~FLUSHW; } if (*mp->b_rptr & FLUSHR) { flushq(RD(q), FLUSHALL); qreply(q, mp); } else break; return; case M_IOCTL: if ((err = ls_m_ioctl(q, mp))) break; return; } switch (err & 0xffff) { case EAGAIN: putq(q, mp); return; case EOPNOTSUPP: if (q->q_next) { putnext(q, mp); return; } } DTRACE; freemsg(mp); /* don't even want to complain */ return; } static void ls_wsrv(queue_t * q) { int err = EOPNOTSUPP; mblk_t *mp; DTRACE; while ((mp = getq(q))) { if (q->q_next && mp->b_datap->db_type < QPCTL && !canputnext(q)) { putbq(q, mp); return; } switch (mp->b_datap->db_type) { case M_DATA: freemsg(mp); /* don't support raw read/write here */ continue; case M_CTL: case M_PROTO: case M_PCPROTO: if ((err = ls_m_proto(q, mp))) break; continue; } switch (err & 0xffff) { case EAGAIN: if (mp->b_datap->db_type < QPCTL) { putbq(q, mp); return; } break; case EOPNOTSUPP: if (q->q_next) { putnext(q, mp); return; } } DTRACE; freemsg(mp); } } static void ls_rput(queue_t * q, mblk_t * mp) { DTRACE; if (mp->b_datap->db_type < QPCTL && (q->q_count || !canputnext(q))) putq(q, mp); else putnext(q, mp); } static void ls_rsrv(queue_t * q) { mblk_t *mp; DTRACE; while ((mp = getq(q))) { if (mp->b_datap->db_type < QPCTL && !canputnext(q)) { putbq(q, mp); return; } putnext(q, mp); } } /* * ------------------------------------------ * * LOWER QUEUE PUT and QUEUE SERVICE routines * * ------------------------------------------ */ static void lk_wput(queue_t * q, mblk_t * mp) { DTRACE; if (mp->b_datap->db_type < QPCTL && (q->q_count || !canputnext(q))) putq(q, mp); else putnext(q, mp); } static void lk_wsrv(queue_t * q) { mblk_t *mp; DTRACE; while ((mp = getq(q))) { if (mp->b_datap->db_type < QPCTL && !canputnext(q)) { putbq(q, mp); return; } putnext(q, mp); } } static void lk_rput(queue_t * q, mblk_t * mp) { int err = EOPNOTSUPP; queue_t *upperq = ((lk_t *) q->q_ptr)->module->rq; DTRACE; if (q->q_count && mp->b_datap->db_type < QPCTL) { putq(q, mp); return; } switch (mp->b_datap->db_type) { case M_DATA: if ((err = lk_m_data(q, mp))) break; return; case M_CTL: case M_PROTO: case M_PCPROTO: if ((err = lk_m_proto(q, mp))) break; return; } switch (err & 0xffff) { case EAGAIN: putq(q, mp); return; case EOPNOTSUPP: putq(upperq, mp); return; } DTRACE; freemsg(mp); } static void lk_rsrv(queue_t * q) { mblk_t *mp; int err = EOPNOTSUPP; queue_t *upperq = ((lk_t *) q->q_ptr)->module->rq; DTRACE; while ((mp = getq(q))) { if (mp->b_datap->db_type < QPCTL && !canput(upperq)) { putbq(q, mp); return; } switch (mp->b_datap->db_type) { case M_DATA: if ((err = lk_m_data(q, mp))) break; continue; case M_CTL: case M_PROTO: case M_PCPROTO: if ((err = lk_m_proto(q, mp))) break; continue; } switch (err & 0xffff) { case EAGAIN: if (mp->b_datap->db_type < QPCTL) { putbq(q, mp); return; } break; case EOPNOTSUPP: putq(upperq, mp); return; } DTRACE; freemsg(mp); } } /* * ======================================================================= * * OPEN and CLOSE * * ======================================================================= */ static lmi_driver_t *ls_drivers = NULL; static int ls_open(queue_t * q, dev_t * devp, int flag, int sflag, cred_t * crp) { int err, i; ls_t *ls; DTRACE; if (q->q_ptr != NULL) return (0); if ((err = lmi_mux_open(q, devp, flag, sflag, crp, ls_drivers, sizeof(ls_t)))) return (err); ls = (ls_t *) q->q_ptr; ls->ucalls = &ls_mux_ucalls; ls->dcalls = &ls_mux_dcalls; /* FIXME: Initialize some of the ls structure here... */ for (i = 0; i < LS_MAX_LINKS; i++) { bufq_init(&ls->llinks[i].cob_buf); bufq_init(&ls->llinks[i].rtr_buf); } return (0); } static int ls_close(queue_t * q, int flag, cred_t * crp) { int err; ls_t *ls = (ls_t *) q->q_ptr; DTRACE; err = lmi_mux_close(q, flag, crp, (ls_ulong *) & ls->timers, LS_MAX_TIMERIDS, (ls_ulong *) & ls->bufids, LS_MAX_BUFCALLS); return (err); } /* * ======================================================================= * * DRIVER Registration (driver registering with us) * * ======================================================================= */ int ls_register_driver(major_t cmajor, int nminor, char *name, lmi_ops_t * ops, ls_dcalls_t * dcalls) { int ret; DTRACE; MOD_INC_USE_COUNT; if ((ret = lmi_register_driver(&ls_drivers, cmajor, &ls_info, nminor, name, ops, dcalls, &ls_mux_ucalls)) < 0) { MOD_DEC_USE_COUNT; return (ret); } return (ret); } int ls_unregister_driver(major_t cmajor) { int err = lmi_unregister_driver(&ls_drivers, cmajor); DTRACE; if (!err) MOD_DEC_USE_COUNT; return (err); } /* * ======================================================================= * * LiS Module Initialization * * ======================================================================= */ static int ls_initialized = 0; #ifndef LIS_REGISTERED static inline void ls_init(void) #else __initfunc(void ls_init(void)) #endif { if (ls_initialized) return; ls_initialized = 1; printk(KERN_INFO LS_BANNER); /* console splash */ #ifndef LIS_REGISTERED if (lis_register_strdev(LS_CMAJOR, &ls_info, LS_NMINOR, ls_minfo.mi_idname) < 0) { cmn_err(CE_NOTE, "ls: couldn't register module\n"); ls_minfo.mi_idnum = 0; } ls_minfo.mi_idnum = 1; #endif #if 0 if (mtp_register_driver(LS_CMAJOR, LS_NMINOR, "sls", &ls_lmi_ops, &ls_drv_ops)) { cmn_err(CE_NOTE, "sls: couldn't register as driver\n"); } #endif }; #ifndef LIS_REGISTERED static inline void ls_terminate(void) #else __initfunc(void ls_terminate(void)) #endif { if (!ls_initialized) return; ls_initialized = 0; #ifndef LIS_REGSITERED if (ls_minfo.mi_idnum) if (lis_unregister_strdev(ls_minfo.mi_idnum) < 0) { cmn_err(CE_WARN, "ls: couldn't unregister module!\n"); } #endif }; /* * ======================================================================= * * Kernel Module Initialization * * ======================================================================= */ #ifdef MODULE int init_module(void) { DTRACE; ls_init(); return (0); } void cleanup_module(void) { DTRACE; ls_terminate(); return; } #endif
|
|||||||||||||||||||||||||||
OpenSS7 SS7 for the Common Man |
Home | Overview | Status | News | Documentation | Resources | About | ||||||||||||||||||||
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |