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/sdti/sdt.c#ident "@(#) $RCSfile: sdt.c,v $ $Name: $($Revision: 0.8.2.10 $) $Date: 2003/04/30 13:07:30 $" static char const ident[] = "$RCSfile: sdt.c,v $ $Name: $($Revision: 0.8.2.10 $) $Date: 2003/04/30 13:07:30 $"; /* * This is an SDT (Signalling Data Terminal) kernel module which provides all * of the capabilities of the SDTI. Drivers which implement the SDLI can * push this module to form an SDTI driver implementation. This permits the * DAEDR, DAEDT, SUERM, AERM and EIM functions to be tested once and 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 <ss7/lmi.h> #include <ss7/lmi_ioctl.h> #include <ss7/sdli.h> #include <ss7/sdli_ioctl.h> #include <ss7/sdti.h> #include <ss7/sdti_ioctl.h> #include "../debug.h" #include "../bufq.h" #include "../priv.h" #include "../lock.h" #include "../queue.h" #include "../allocb.h" #include "../timer.h" #define SDT_DESCRIP "SS7/SDT: (Signalling Data Terminal) STREAMS MODULE." #define SDT_COPYRIGHT "Copyright (c) 1997-2002 OpenSS7 Corporation. All Rights Reserved." #define SDT_DEVICES "Supports OpenSS7 SDL drivers." #define SDT_CONTACT "Brian Bidulock <bidulock@openss7.org>" #define SDT_LICENSE "GPL" #define SDT_BANNER SDT_DESCRIP "\n" \ SDT_COPYRIGHT "\n" \ SDT_DEVICES "\n" \ SDT_CONTACT "\n" MODULE_AUTHOR(SDT_CONTACT); MODULE_DESCRIPTION(SDT_DESCRIP); MODULE_SUPPORTED_DEVICE(SDT_DEVICES); #ifdef MODULE_LICENSE MODULE_LICENSE(SDT_LICENSE); #endif /* * ======================================================================= * * STREAMS Definitions * * ======================================================================= */ #define SDT_MOD_ID SDT_IOC_MAGIC #define SDT_MOD_NAME "sdt" STATIC struct module_info sdt_rinfo = { mi_idnum:SDT_MOD_ID, /* Module ID number */ mi_idname:SDT_MOD_NAME "-rd", /* Module name */ mi_minpsz:1, /* Min packet size accepted */ mi_maxpsz:128, /* Max packet size accepted */ mi_hiwat:1, /* Hi water mark */ mi_lowat:0, /* Lo water mark */ }; STATIC struct module_info sdt_winfo = { mi_idnum:SDT_MOD_ID, /* Module ID number */ mi_idname:SDT_MOD_NAME "-wr", /* Module name */ mi_minpsz:1, /* Min packet size accepted */ mi_maxpsz:280, /* Max packet size accepted */ mi_hiwat:1, /* Hi water mark */ mi_lowat:0, /* Lo water mark */ }; STATIC int sdt_open(queue_t *, dev_t *, int, int, cred_t *); STATIC int sdt_close(queue_t *, int, cred_t *); STATIC struct qinit sdt_rinit = { qi_putp:ss7_oput, /* Read put (message from below) */ qi_qopen:sdt_open, /* Each open */ qi_qclose:sdt_close, /* Last close */ qi_minfo:&sdt_rinfo, /* Information */ }; STATIC struct qinit sdt_winit = { qi_putp:ss7_iput, /* Write put (message from above) */ qi_minfo:&sdt_winfo, /* Information */ }; STATIC struct streamtab sdt_info = { st_rdinit:&sdt_rinit, /* Upper read queue */ st_wrinit:&sdt_winit, /* Upper write queue */ }; /* * ======================================================================== * * Private structure * * ======================================================================== */ typedef struct sdt_path { uint residue; /* residue bits */ uint rbits; /* number of residue bits */ ushort bcc; /* crc for message */ uint state; /* state */ uint mode; /* path mode */ uint type; /* path frame type */ uint bytes; /* number of whole bytes */ mblk_t *msg; /* message */ mblk_t *nxt; /* message chain block */ mblk_t *cmp; /* repeat/compress buffer */ uint repeat; /* repeat/compress count */ } sdt_path_t; typedef struct sdt { STR_DECLARATION (struct sdt); /* streamd declaration */ sdt_path_t tx; /* transmit path variables */ sdt_path_t rx; /* receive path variables */ uint rx_octets; /* no received octets */ sdt_timers_t timers; /* SDT protocol timers */ lmi_option_t option; /* LMI protocol and variant options */ sdt_statem_t statem; /* SDT state machine variables */ sdt_config_t config; /* SDT configuration options */ sdt_notify_t notify; /* SDT notification options */ sdt_stats_t stats; /* SDT statistics */ sdt_stats_t stamp; /* SDT statistics timestamps */ lmi_sta_t statsp; /* SDT statistics periods */ } sdt_t; #define SDT_PRIV(__q) ((struct sdt *)(__q)->q_ptr) struct sdt *sdt_opens = NULL; STATIC struct sdt *sdt_alloc_priv(queue_t *, struct sdt **, dev_t *, cred_t *); STATIC struct sdt *sdt_get(struct sdt *); STATIC void sdt_put(struct sdt *); STATIC void sdt_free_priv(queue_t *); struct lmi_option lmi_default = { pvar:SS7_PVAR_ITUT_96, popt:0, }; struct sdt_config sdt_default = { Tin:4, /* AERM normal proving threshold */ Tie:1, /* AERM emergency proving threshold */ T:64, /* SUERM error threshold */ D:256, /* SUERM error rate parameter */ t8:100 * HZ / 1000, /* T8 timeout */ Te:577169, /* EIM error threshold */ De:9308, /* EIM correct decrement */ Ue:144292, /* EIM error increment */ N:16, /* octets per su in OCM */ m:272, /* maximum SIF size */ b:8, /* transmit block size */ f:SDT_FLAGS_ONE, /* one flag between frames */ }; /* * ======================================================================== * * PRIMITIVES * * ======================================================================== */ /* * ------------------------------------------------------------------------ * * Primitives sent upstream * * ------------------------------------------------------------------------ */ /* * M_ERROR * ----------------------------------- */ STATIC int m_error(queue_t *q, struct sdt *s, int err) { mblk_t *mp; if ((mp = ss7_allocb(q, 2, BPRI_MED))) { mp->b_datap->db_type = M_ERROR; *(mp->b_wptr)++ = err < 0 ? -err : err; *(mp->b_wptr)++ = err < 0 ? -err : err; s->i_state = LMI_UNUSABLE; printd(("%s: %p: <- M_ERROR\n", SDT_MOD_NAME, s)); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } #if 0 /* * M_HANGUP * ----------------------------------- */ STATIC int m_hangup(queue_t *q, struct sdt *s, int err) { mblk_t *mp; if ((mp = ss7_allocb(q, 2, BPRI_MED))) { mp->b_datap->db_type = M_HANGUP; *(mp->b_wptr)++ = err < 0 ? -err : err; *(mp->b_wptr)++ = err < 0 ? -err : err; s->i_state = LMI_UNUSABLE; printd(("%s: %p: <- M_HANGUP\n", SDT_MOD_NAME, s)); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LMI_INFO_ACK * ----------------------------------- * NOTE: before pushing SDT as a module, a STYLE2 SDL driver should have * already been attached so that the SDT module can run as a STYLE1 module. */ STATIC INLINE int lmi_info_ack(queue_t *q, struct sdt *s) { mblk_t *mp; lmi_info_ack_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_INFO_ACK; p->lmi_version = 1; p->lmi_state = s->i_state; p->lmi_max_sdu = s->config.m + 1 + ((s->option.popt & SS7_POPT_XSN) ? 6 : 3); p->lmi_min_sdu = ((s->option.popt & SS7_POPT_XSN) ? 6 : 3); p->lmi_header_len = 0; p->lmi_ppa_style = LMI_STYLE1; /* only STYLE1 for modules */ printd(("%s: %p: <- LMI_INFO_ACK\n", SDT_MOD_NAME, s)); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LMI_OK_ACK * ----------------------------------- */ STATIC INLINE int lmi_ok_ack(queue_t *q, struct sdt *s, long prim) { mblk_t *mp; lmi_ok_ack_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_OK_ACK; p->lmi_correct_primitive = prim; switch (s->i_state) { case LMI_ATTACH_PENDING: s->i_state = LMI_DISABLED; break; case LMI_DETACH_PENDING: s->i_state = LMI_UNATTACHED; break; } p->lmi_state = s->i_state; printd(("%s: %p: <- LMI_OK_ACK\n", SDT_MOD_NAME, s)); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } #endif /* * LMI_ERROR_ACK * ----------------------------------- */ STATIC INLINE int lmi_error_ack(queue_t *q, struct sdt *s, long prim, ulong reason, ulong errno) { mblk_t *mp; lmi_error_ack_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_ERROR_ACK; p->lmi_errno = errno; p->lmi_reason = reason; p->lmi_error_primitive = prim; switch (s->i_state) { case LMI_ATTACH_PENDING: s->i_state = LMI_UNATTACHED; break; case LMI_DETACH_PENDING: s->i_state = LMI_DISABLED; break; case LMI_ENABLE_PENDING: s->i_state = LMI_DISABLED; break; case LMI_DISABLE_PENDING: s->i_state = LMI_ENABLED; break; default: break; } p->lmi_state = s->i_state; printd(("%s: %p: <- LMI_ERROR_ACK\n", SDT_MOD_NAME, s)); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } #if 0 /* * LMI_ENABLE_CON * ----------------------------------- */ STATIC INLINE int lmi_enable_con(queue_t *q, struct sdt *s) { mblk_t *mp; lmi_enable_con_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_ENABLE_CON; p->lmi_state = s->i_state; printd(("%s: %p: <- LMI_ENABLE_CON\n", SDT_MOD_NAME, s)); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LMI_DISABLE_CON * ----------------------------------- */ STATIC INLINE int lmi_disable_con(queue_t *q, struct sdt *s) { mblk_t *mp; lmi_disable_con_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_DISABLE_CON; p->lmi_state = s->i_state; printd(("%s: %p: <- LMI_DISABLE_CON\n", SDT_MOD_NAME, s)); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LMI_OPTMGMT_ACK * ----------------------------------- */ STATIC INLINE int lmi_optmgmt_ack(queue_t *q, struct sdt *s, ulong flags, caddr_t opt_ptr, size_t opt_len) { mblk_t *mp; lmi_optmgmt_ack_t *p; if ((mp = ss7_allocb(q, sizeof(*p) + opt_len, BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_OPTMGMT_ACK; p->lmi_opt_length = opt_len; p->lmi_opt_offset = opt_len ? sizeof(*p) : 0; p->lmi_flags = flags; bcopy(opt_ptr, mp->b_wptr, opt_len); mp->b_wptr += opt_len; printd(("%s: %p: <- LMI_OPTMGMT_ACK\n", SDT_MOD_NAME, s)); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LMI_ERROR_IND * ----------------------------------- */ STATIC INLINE int lmi_error_ind(queue_t *q, struct sdt *s, long error, long reason) { mblk_t *mp; lmi_error_ind_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_ERROR_IND; p->lmi_errno = error; p->lmi_reason = reason; p->lmi_state = s->i_state; printd(("%s: %p: <- LMI_ERROR_IND\n", SDT_MOD_NAME, s)); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LMI_STATS_IND * ----------------------------------- */ STATIC INLINE int lmi_stats_ind(queue_t *q, struct sdt *s) { mblk_t *mp; lmi_stats_ind_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_STATS_IND; p->lmi_interval = 0; p->lmi_timestamp = jiffies; printd(("%s: %p: <- LMI_STATS_IND\n", SDT_MOD_NAME, s)); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } #endif /* * LMI_EVENT_IND * ----------------------------------- */ STATIC INLINE int lmi_event_ind(queue_t *q, struct sdt *s, ulong oid, ulong level, caddr_t inf_ptr, size_t inf_len) { mblk_t *mp; lmi_event_ind_t *p; if ((mp = ss7_allocb(q, sizeof(*p) + inf_len, BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_EVENT_IND; p->lmi_objectid = oid; p->lmi_timestamp = jiffies; p->lmi_severity = level; bcopy(inf_ptr, mp->b_wptr, inf_len); mp->b_wptr += inf_len; printd(("%s: %p: <- LMI_EVENT_IND\n", SDT_MOD_NAME, s)); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SDT_RC_SIGNAL_UNIT_IND * ----------------------------------- */ STATIC INLINE int sdt_rc_signal_unit_ind(queue_t *q, struct sdt *s, mblk_t *dp, ulong count) { if (count == 1) { printd(("%s: %p: <- M_DATA [%d]\n", SDT_MOD_NAME, s, msgdsize(dp))); putnext(s->oq, dp); return (QR_DONE); } else if (count > 1) { mblk_t *mp; sdt_rc_signal_unit_ind_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->sdt_primitive = SDT_RC_SIGNAL_UNIT_IND; p->sdt_count = count; mp->b_cont = dp; printd(("%s: %p: <- SDT_RC_SIGNAL_UNIT_IND [%lu x %d]\n", SDT_MOD_NAME, s, count, msgdsize(dp))); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } swerr(); return (-EFAULT); } /* * SDT_RC_CONGESTION_ACCEPT_IND * ----------------------------------- */ STATIC INLINE int sdt_rc_congestion_accept_ind(queue_t *q, struct sdt *s) { mblk_t *mp; sdt_rc_congestion_accept_ind_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->sdt_primitive = SDT_RC_CONGESTION_ACCEPT_IND; printd(("%s: %p: <- SDT_RC_CONGESTION_ACCEPT_IND\n", SDT_MOD_NAME, s)); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SDT_RC_CONGESTION_DISCARD_IND * ----------------------------------- */ STATIC INLINE int sdt_rc_congestion_discard_ind(queue_t *q, struct sdt *s) { mblk_t *mp; sdt_rc_congestion_discard_ind_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->sdt_primitive = SDT_RC_CONGESTION_DISCARD_IND; printd(("%s: %p: <- SDT_RC_CONGESTION_DISCARD_IND\n", SDT_MOD_NAME, s)); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SDT_RC_NO_CONGESTION_IND * ----------------------------------- */ STATIC INLINE int sdt_rc_no_congestion_ind(queue_t *q, struct sdt *s) { mblk_t *mp; sdt_rc_no_congestion_ind_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->sdt_primitive = SDT_RC_NO_CONGESTION_IND; printd(("%s: %p: <- SDT_RC_NO_CONGESTION_IND\n", SDT_MOD_NAME, s)); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SDT_IAC_CORRECT_SU_IND * ----------------------------------- */ STATIC INLINE int sdt_iac_correct_su_ind(queue_t *q, struct sdt *s) { mblk_t *mp; sdt_iac_correct_su_ind_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->sdt_primitive = SDT_IAC_CORRECT_SU_IND; printd(("%s: %p: <- SDT_IAC_CORRECT_SU_IND\n", SDT_MOD_NAME, s)); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SDT_IAC_ABORT_PROVING_IND * ----------------------------------- */ STATIC INLINE int sdt_iac_abort_proving_ind(queue_t *q, struct sdt *s) { mblk_t *mp; sdt_iac_abort_proving_ind_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->sdt_primitive = SDT_IAC_ABORT_PROVING_IND; printd(("%s: %p: <- SDT_IAC_ABORT_PROVING_IND\n", SDT_MOD_NAME, s)); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SDT_LSC_LINK_FAILURE_IND * ----------------------------------- */ STATIC INLINE int sdt_lsc_link_failure_ind(queue_t *q, struct sdt *s) { mblk_t *mp; sdt_lsc_link_failure_ind_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->sdt_primitive = SDT_LSC_LINK_FAILURE_IND; printd(("%s: %p: <- SDT_LSC_LINK_FAILURE_IND\n", SDT_MOD_NAME, s)); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } #if 0 /* We let back-enabling do this for us */ /* * SDT_TXC_TRANSMISSION_REQUEST_IND * ----------------------------------- */ STATIC INLINE int sdt_txc_transmission_request_ind(queue_t *q, struct sdt *s) { mblk_t *mp; sdt_txc_transmission_request_ind_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->sdt_primitive = SDT_TXC_TRANSMISSION_REQUEST_IND; printd(("%s: %p: <- SDT_TXC_TRANSMISSION_REQUEST_IND\n", SDT_MOD_NAME, s)); putnext(s->oq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } #endif /* * ======================================================================== * * PRIMITIVES Sent Downstream * * ======================================================================== */ /* * LMI_INFO_REQ * ----------------------------------- */ STATIC INLINE int sdl_info_req(queue_t *q, struct sdt *s) { mblk_t *mp; lmi_info_req_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_INFO_REQ; printd(("%s: %p: LMI_INFO_REQ ->\n", SDT_MOD_NAME, s)); putnext(s->iq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } #if 0 /* We don't need any of these because these are just passed along. */ /* * LMI_ATTACH_REQ * ----------------------------------- */ STATIC INLINE int sdl_attach_req(queue_t *q, struct sdt *s, caddr_t ppa_ptr, size_t ppa_len) { mblk_t *mp; lmi_attach_req_t *p; if ((mp = ss7_allocb(q, sizeof(*p) + ppa_len, BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_ATTACH_REQ; bcopy(ppa_ptr, mp->b_wptr, ppa_len); mp->b_wptr += ppa_len; printd(("%s: %p: LMI_ATTACH_REQ ->\n", SDT_MOD_NAME, s)); putnext(s->iq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LMI_DETACH_REQ * ----------------------------------- */ STATIC INLINE int sdl_detach_req(queue_t *q, struct sdt *s) { mblk_t *mp; lmi_detach_req_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_DETACH_REQ; printd(("%s: %p: LMI_DETACH_REQ ->\n", SDT_MOD_NAME, s)); putnext(s->iq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LMI_ENABLE_REQ * ----------------------------------- */ STATIC INLINE int sdl_enable_req(queue_t *q, struct sdt *s) { mblk_t *mp; lmi_enable_req_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_ENABLE_REQ; printd(("%s: %p: LMI_ENABLE_REQ ->\n", SDT_MOD_NAME, s)); putnext(s->iq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LMI_DISABLE_REQ * ----------------------------------- */ STATIC INLINE int sdl_disable_req(queue_t *q, struct sdt *s) { mblk_t *mp; lmi_disable_req_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_DISABLE_REQ; printd(("%s: %p: LMI_DISABLE_REQ ->\n", SDT_MOD_NAME, s)); putnext(s->iq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * LMI_OPTMGMT_REQ * ----------------------------------- */ STATIC INLINE int sdl_optmgmt_req(queue_t *q, struct sdt *s, long flags, caddr_t opt_ptr, size_t opt_len) { mblk_t *mp; lmi_optmgmt_req_t *p; if ((mp = ss7_allocb(q, sizeof(*p) + opt_len, BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->lmi_primitive = LMI_OPTMGMT_REQ; p->lmi_opt_length = opt_len; p->lmi_opt_offset = opt_len ? sizeof(*p) : 0; p->lmi_mgmt_flags = flags; bcopy(opt_ptr, mp->b_wptr, opt_len); mp->b_wptr += opt_len; printd(("%s: %p: LMI_OPTMGMT_REQ ->\n", SDT_MOD_NAME, s)); putnext(s->iq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } #endif #if 0 /* * SDL_BITS_FOR_TRANSMISSION_REQ * ----------------------------------- * This is the non-prefferred method for sending transmitted bits. The * preferred method is to send just an M_DATA block. */ STATIC INLINE int sdl_bits_for_transmission_req(queue_t *q, struct sdt *s, mblk_t *dp) { mblk_t *mp; sdl_bits_for_transmission_req_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->sdl_primitive = SDL_BITS_FOR_TRANSMISSION_REQ; mp->b_cont = dp; printd(("%s: %p: SDL_BITS_FOR_TRANSMISSION [%d] ->\n", SDT_MOD_NAME, s, msgdsize(dp))); putnext(s->iq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SDL_CONNECT_REQ * ----------------------------------- */ STATIC INLINE int sdl_connect_req(queue_t *q, struct sdt *s) { mblk_t *mp; sdl_connect_req_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->sdl_primitive = SDL_CONNECT_REQ; printd(("%s: %p: SDL_CONNECT_REQ ->\n", SDT_MOD_NAME, s)); putnext(s->iq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } /* * SDL_DISCONNECT_REQ * ----------------------------------- */ STATIC INLINE int sdl_disconnect_req(queue_t *q, struct sdt *s) { mblk_t *mp; sdl_disconnect_req_t *p; if ((mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->sdl_primitive = SDL_DISCONNECT_REQ; printd(("%s: %p: SDL_DISCONNECT_REQ ->\n", SDT_MOD_NAME, s)); putnext(s->iq, mp); return (QR_DONE); } rare(); return (-ENOBUFS); } #endif /* * ========================================================================= * * PROTOCOL STATE MACHINE FUNCTIONS * * ========================================================================= */ /* * ------------------------------------------------------------------------- * * Timers * * ------------------------------------------------------------------------- */ enum { tall, t8 }; SS7_DECLARE_TIMER(SDT_MOD_NAME, sdt, t8, config); STATIC INLINE void __sdt_timer_stop(struct sdt *s, const uint t) { int single = 1; switch (t) { case tall: single = 0; /* fall through */ case t8: sdt_stop_timer_t8(s); if (single) break; /* fall through */ break; default: swerr(); break; } } STATIC INLINE void sdt_timer_stop(struct sdt *s, const uint t) { int flags; lis_spin_lock_irqsave(&s->lock, &flags); { __sdt_timer_stop(s, t); } lis_spin_unlock_irqrestore(&s->lock, &flags); } STATIC INLINE void sdt_timer_start(struct sdt *s, const uint t) { int flags; lis_spin_lock_irqsave(&s->lock, &flags); { __sdt_timer_stop(s, t); switch (t) { case t8: sdt_start_timer_t8(s); break; default: swerr(); break; } } lis_spin_unlock_irqrestore(&s->lock, &flags); } /* * ------------------------------------------------------------------------- * * State Machine * * ------------------------------------------------------------------------- */ STATIC INLINE int sdt_aerm_su_in_error(queue_t *q, struct sdt *s) { int err; if (s->statem.aerm_state == SDT_STATE_MONITORING) { s->statem.Ca++; if (s->statem.Ca == s->statem.Ti) { s->statem.aborted_proving = 1; if ((err = sdt_iac_abort_proving_ind(q, s))) { s->statem.Ca--; return (err); } s->statem.aerm_state = SDT_STATE_IDLE; } } return (QR_DONE); } STATIC INLINE int sdt_aerm_correct_su(queue_t *q, struct sdt *s) { int err; if (s->statem.aerm_state == SDT_STATE_IDLE) { if (s->statem.aborted_proving) { if ((err = sdt_iac_correct_su_ind(q, s))) return (err); s->statem.aborted_proving = 0; } } return (QR_DONE); } STATIC INLINE int sdt_suerm_start(queue_t *q, struct sdt *s) { s->statem.Cs = 0; s->statem.Ns = 0; s->statem.suerm_state = SDT_STATE_IN_SERVICE; return (QR_DONE); } STATIC INLINE void sdt_suerm_stop(queue_t *q, struct sdt *s) { s->statem.suerm_state = SDT_STATE_IDLE; } STATIC INLINE int sdt_suerm_su_in_error(queue_t *q, struct sdt *s) { int err; if (s->statem.suerm_state == SDT_STATE_IN_SERVICE) { s->statem.Cs++; if (s->statem.Cs >= s->config.T) { if ((err = sdt_lsc_link_failure_ind(q, s))) { s->statem.Ca--; return (err); } s->statem.suerm_state = SDT_STATE_IDLE; return (QR_DONE); } s->statem.Ns++; if (s->statem.Ns >= s->config.D) { s->statem.Ns = 0; if (s->statem.Cs) s->statem.Cs--; } } return (QR_DONE); } STATIC INLINE void sdt_eim_su_in_error(queue_t *q, struct sdt *s) { if (s->statem.eim_state == SDT_STATE_MONITORING) s->statem.interval_error = 1; } STATIC INLINE void sdt_suerm_correct_su(queue_t *q, struct sdt *s) { if (s->statem.suerm_state == SDT_STATE_IN_SERVICE) { s->statem.Ns++; if (s->statem.Ns >= s->config.D) { s->statem.Ns = 0; if (s->statem.Cs) s->statem.Cs--; } } } STATIC INLINE void sdt_eim_correct_su(queue_t *q, struct sdt *s) { if (s->statem.eim_state == SDT_STATE_MONITORING) s->statem.su_received = 1; } STATIC INLINE int sdt_eim_start(queue_t *q, struct sdt *s) { s->statem.Ce = 0; s->statem.interval_error = 0; s->statem.su_received = 0; sdt_timer_start(s, t8); s->statem.eim_state = SDT_STATE_MONITORING; return (QR_DONE); } STATIC INLINE void sdt_eim_stop(queue_t *q, struct sdt *s) { s->statem.eim_state = SDT_STATE_IDLE; sdt_timer_stop(s, t8); } STATIC INLINE int sdt_daedr_correct_su(queue_t *q, struct sdt *s) { sdt_eim_correct_su(q, s); sdt_suerm_correct_su(q, s); return sdt_aerm_correct_su(q, s); } STATIC INLINE int sdt_daedr_su_in_error(queue_t *q, struct sdt *s) { int err; sdt_eim_su_in_error(q, s); if ((err = sdt_suerm_su_in_error(q, s))) return (err); if ((err = sdt_aerm_su_in_error(q, s))) return (err); return (QR_DONE); } STATIC INLINE int sdt_daedr_received_bits(queue_t *q, struct sdt *s, mblk_t *mp) { sdt_path_t *rx = &s->rx; int err, pos, match = 0, len = msgdsize(mp); int hlen = (s->option.popt & SS7_POPT_XSN) ? 6 : 3; if (rx->cmp) { if (len < hlen + 3 && len >= hlen && len == msgdsize(rx->cmp)) for (match = 1, pos = 0; pos < len; pos++) if (!(match = (mp->b_rptr[pos] == rx->cmp->b_rptr[pos]))) break; if (match) { rx->repeat++; s->stats.rx_sus_compressed++; freemsg(mp); sdt_daedr_correct_su(q, s); return (QR_ABSORBED); } else if (rx->repeat > 0 && (err = sdt_rc_signal_unit_ind (q, s, xchg(&rx->cmp, NULL), xchg(&rx->repeat, 0))) != QR_ABSORBED) goto overflow; } if (!match && len < hlen + 3 && (rx->cmp || (rx->cmp = allocb(len, BPRI_MED)))) { bcopy(mp->b_rptr, rx->cmp->b_rptr, len); rx->cmp->b_wptr = rx->cmp->b_rptr + len; rx->repeat = 0; } sdt_daedr_correct_su(q, s); if ((err = sdt_rc_signal_unit_ind(q, s, mp, 1)) == QR_ABSORBED) return (QR_ABSORBED); overflow: s->stats.rx_buffer_overflows++; return (err); } #if 0 STATIC INLINE int sdt_daedt_transmission_request(queue_t *q, struct sdt *s) { return sdt_txc_transmission_request_ind(q, s); } #endif /* * ======================================================================== * * Soft-HDLC * * ======================================================================== */ #define SDT_TX_STATES 5 #define SDT_RX_STATES 14 #define SDT_TX_BUFSIZE PAGE_SIZE #define SDT_RX_BUFSIZE PAGE_SIZE #define SDT_CRC_TABLE_LENGTH 512 #define SDT_TX_TABLE_LENGTH (2* SDT_TX_STATES * 256) #define SDT_RX_TABLE_LENGTH (2* SDT_RX_STATES * 256) typedef struct tx_entry { uint bit_string:10; /* the output string */ uint bit_length:4; /* length in excess of 8 bits of output string */ uint state:3; /* new state */ } tx_entry_t __attribute__ ((packed)); typedef struct rx_entry { uint bit_string:16; uint bit_length:4; uint state:4; uint sync:1; uint hunt:1; uint flag:1; uint idle:1; } rx_entry_t __attribute__ ((packed)); typedef uint16_t bc_entry_t; STATIC bc_entry_t *bc_table = NULL; STATIC tx_entry_t *tx_table = NULL; STATIC rx_entry_t *rx_table = NULL; STATIC rx_entry_t *rx_table7 = NULL; STATIC size_t bc_order = 0; STATIC size_t tx_order = 0; STATIC size_t rx_order = 0; STATIC INLINE tx_entry_t *tx_index8(uint j, uint k) { return &tx_table[(j << 8) | k]; } STATIC INLINE rx_entry_t *rx_index7(uint j, uint k) { return &rx_table7[(j << 8) | k]; } STATIC INLINE rx_entry_t *rx_index8(uint j, uint k) { return &rx_table[(j << 8) | k]; } #ifdef _DEBUG STATIC INLINE void printb(uint8_t byte) { uint8_t mask = 0x80; while (mask) { if (mask & byte) printd(("1")); else printd(("0")); } } STATIC INLINE void printbs(uint str, uint len) { uint mask = (1 << len); while (mask >>= 1) { if (mask & str) printd(("1")); else printd(("0")); } } STATIC INLINE void printr(rx_entry_t * r) { printd(("rx(%2d) %d%d%d%d ", r->state, r->flag, r->sync, r->hunt, r->idle)); printbs(r->bit_string, r->bit_length); printd(("\n")); } STATIC INLINE void printt(tx_entry_t * t) { printd(("tx(%2d) ", t->state)); printbs(t->bit_string, t->bit_length + 8); printd(("\n")); } #else STATIC INLINE void printb(uint8_t byte) { } STATIC INLINE void printr(rx_entry_t * r) { } STATIC INLINE void printt(tx_entry_t * t) { } #endif /* * TX REPEAT * ---------------------------------------- * Set up the FISU/LSSU repeat buffer for a new message for transmission. * * We need to set up the repeat buffer with every new message. The repeat * buffer contains a FISU for transmitted MSUs (if non-PCR). It contains the * FISU, LSSU or 2-byte LSSU for transmitted FISUs and LSSUs. For SIBs it * contains a FISU (if non-PCR), for other LSSUs it contains the LSSU. */ STATIC int sdt_tx_repeat(queue_t *q, struct sdt *s, mblk_t *mp) { mblk_t *cp; int len, hlen, clen; if ((len = msgdsize(mp)) < (hlen = (s->option.popt & SS7_POPT_XSN) ? 6 : 3)) { ptrace(("%s: %p: ERROR: user violated minimum size\n", SDT_MOD_NAME, s)); goto dont_repeat; } if (len > hlen + 2 || ((len == hlen + 1 || len == hlen + 2) && (mp->b_rptr[hlen] & 0x7) == 5)) { /* MSU or SIB */ if (s->option.popt & SS7_POPT_PCR) goto dont_repeat; clen = hlen; } else { /* FISU or LSSU */ clen = len; } if (!(cp = s->tx.cmp) && !(cp = s->tx.cmp = ss7_allocb(q, clen, BPRI_MED))) return (-ENOBUFS); bcopy(mp->b_rptr, cp->b_rptr, clen); cp->b_wptr = cp->b_rptr + clen; if (!(s->option.popt & SS7_POPT_XSN)) ((uint8_t *) cp->b_rptr)[2] = clen - hlen; else ((uint16_t *) cp->b_rptr)[2] = clen - hlen; return (0); dont_repeat: if (s->tx.cmp) freemsg(xchg(&s->tx.cmp, NULL)); return (0); } /* * TX BUFFER * ---------------------------------------- * Pick up another TX buffer from the queue or a repeat frame. */ STATIC mblk_t *sdt_tx_buffer(queue_t *q, struct sdt *s) { mblk_t *dp = NULL; int flags; /* lock down while we traverse queue */ lis_spin_lock_irqsave(&s->qlock, &flags); { mblk_t *mp; for (mp = s->iq->q_first; mp; mp = mp->b_next) { switch (mp->b_datap->db_type) { case M_DATA: if (sdt_tx_repeat == 0) { dp = mp; rmvq(s->iq, dp); } break; case M_PROTO: if (*((ulong *) mp->b_rptr) != SDT_DAEDT_TRANSMISSION_REQ) continue; if (sdt_tx_repeat == 0) { dp = mp->b_cont; rmvq(s->iq, mp); freeb(mp); } break; default: continue; } break; } } lis_spin_unlock_irqrestore(&s->qlock, &flags); if (!dp && (dp = s->tx.cmp)) { fixme(("Peg some stats\n")); } return (dp); } /* * TX BITSTUFF * ---------------------------------------- * Bitstuff an octet and shift residue for output. */ STATIC INLINE void sdt_tx_bitstuff(sdt_path_t * tx, unsigned char byte) { tx_entry_t *t = tx_index8(tx->state, byte); tx->state = t->state; tx->residue |= t->bit_string << tx->rbits; tx->rbits += t->bit_length + 8; } #define TX_MODE_IDLE 0 /* generating mark idle */ #define TX_MODE_FLAG 1 /* generating flag idle */ #define TX_MODE_BOF 2 /* generating bof flag */ #define TX_MODE_MOF 3 /* generating frames */ #define TX_MODE_BCC 4 /* generating bcc bytes */ /* * TX BLOCK * ---------------------------------------- * Generate blocks for transmission. We generate entire transmit blocks. If * there are not sufficient messages to build the transmit blocks we will * repeat FISU/LSSU or idle flags. */ STATIC void sdt_tx_block(queue_t *q, struct sdt *s) { mblk_t *bp; register sdt_path_t *tx = &s->tx; sdt_stats_t *stats = &s->stats; #if 0 int bits = (s->config.iftype == SDL_TYPE_DS0A) ? 7 : 8; #else const int bits = 8; #endif while (canputnext(s->iq)) { if (!(bp = ss7_allocb(q, s->config.b, BPRI_MED))) break; /* bufcall will bring us back */ if (tx->mode == TX_MODE_IDLE || tx->mode == TX_MODE_FLAG) { if (!tx->nxt) { next_message: if (tx->msg && tx->msg != tx->cmp) freemsg(tx->msg); if ((tx->msg = tx->nxt = sdt_tx_buffer(q, s))) tx->mode = TX_MODE_BOF; } } /* check if transmission block complete */ while (bp->b_wptr < bp->b_rptr + s->config.b) { /* drain residue bits, if necessary */ if (tx->rbits >= bits) { drain_rbits: /* drain residue bits */ if (bits == 8) *bp->b_wptr++ = tx->residue; else *bp->b_wptr++ = tx->residue & 0x7f; tx->residue >>= bits; tx->rbits -= bits; continue; } switch (tx->mode) { case TX_MODE_IDLE: /* mark idle */ tx->residue |= 0xff << tx->rbits; tx->rbits += 8; goto drain_rbits; case TX_MODE_FLAG: /* idle flags */ tx->residue |= 0x7e << tx->rbits; tx->rbits += 8; goto drain_rbits; case TX_MODE_BOF: /* add opening flag (also closing flag) */ switch (s->config.f) { case SDT_FLAGS_ONE: tx->residue |= 0x7e << tx->rbits; tx->rbits += 8; break; case SDT_FLAGS_SHARED: tx->residue |= 0x3f7e << tx->rbits; tx->rbits += 15; break; case SDT_FLAGS_TWO: tx->residue |= 0x7e7e << tx->rbits; tx->rbits += 16; break; default: case SDT_FLAGS_THREE: tx->residue |= 0x7e7e7e << tx->rbits; tx->rbits += 24; break; } tx->state = 0; tx->bcc = 0x00ff; tx->mode = TX_MODE_MOF; goto drain_rbits; case TX_MODE_MOF: /* transmit frame bytes */ if (tx->nxt->b_rptr < tx->nxt->b_wptr || (tx->nxt = tx->nxt->b_cont)) { /* continuing in message */ uint byte = *(tx->nxt->b_rptr)++; tx->bcc = (tx->bcc >> 8) ^ bc_table[(tx->bcc ^ byte) & 0x00ff]; sdt_tx_bitstuff(tx, byte); stats->tx_bytes++; } else { /* finished message: add 1st bcc byte */ sdt_tx_bitstuff(tx, tx->bcc & 0x00ff); tx->mode = TX_MODE_BCC; } goto drain_rbits; case TX_MODE_BCC: /* add 2nd bcc byte */ sdt_tx_bitstuff(tx, tx->bcc >> 8); stats->tx_sus++; tx->mode = TX_MODE_FLAG; goto next_message; } swerr(); } putnext(q, bp); } } /* * RX COMPRESS * ---------------------------------------- * Check for RX compression. Returns 1 when compression in effect, 0 * otherwise. */ STATIC INLINE int sdt_rx_compress(queue_t *q, struct sdt *s, mblk_t *mp) { mblk_t *cp = s->rx.cmp; int len1 = msgdsize(mp); int len2 = cp ? msgdsize(cp) : 0; int len_max = (s->option.popt & SS7_POPT_XSN) ? 8 : 5; if (len1 > len_max) { // printd(("sdt: len1 = %d > len_max = %d\n", len1, len_max)); goto failure; } if (len1 != len2) { // printd(("sdt: len1 = %d != len2 = %d\n", len1, len2)); goto failure; } else { int pos; // pullupmsg(mp, len1); for (pos = 0; pos < len1; pos++) if (cp->b_rptr[pos] != mp->b_rptr[pos]) { // printd(("sdt: mismatch at byte %d\n", pos + 1)); goto failure; } return (1); } failure: return (0); } /* * RX LINKB * ---------------------------------------- * Link a buffer to existing message or create new message with buffer. */ STATIC INLINE void sdt_rx_linkb(sdt_path_t * rx) { if (rx->msg) linkb(rx->msg, rx->nxt); else rx->msg = rx->nxt; rx->nxt = NULL; return; } #define RX_MODE_HUNT 0 /* hunting for flags */ #define RX_MODE_SYNC 1 /* between frames */ #define RX_MODE_MOF 2 /* middle of frame */ /* * RX BLOCK * ---------------------------------------- * Process a receive block for a channel or span. We process all of the * octets in the receive block. Any complete messages will be delivered to * the upper layer if the upper layer is not congested. If the upper layer * is congested we discard the message and indicate receive congestion. The * upper layer should be sensitive to its receive queue backlog and start * sending SIB when required. We do not use backenabling from the upper * layer. We merely start discarding complete messages when the upper layer * is congested. */ STATIC void sdt_rx_block(queue_t *q, struct sdt *s, mblk_t *dp) { register sdt_path_t *rx = &s->rx; sdt_stats_t *stats = &s->stats; while (dp->b_rptr < dp->b_wptr) { rx_entry_t *r; #if 0 if (s->config.iftype != SDL_TYPE_DS0A) #endif r = rx_index8(rx->state, *dp->b_rptr++); #if 0 else r = rx_index7(rx->state, *dp->b_rptr++); #endif rx->state = r->state; switch (rx->mode) { case RX_MODE_MOF: if (!r->sync && r->bit_length) { rx->residue |= r->bit_string << rx->rbits; rx->rbits += r->bit_length; } if (!r->flag) { if (r->hunt || r->idle) goto aborted; while (rx->rbits > 16) { if (rx->nxt && rx->nxt->b_wptr >= rx->nxt->b_datap->db_lim) sdt_rx_linkb(rx); if (!rx->nxt && !(rx->nxt = allocb(FASTBUF, BPRI_HI))) goto buffer_overflow; rx->bcc = (rx->bcc >> 8) ^ bc_table[(rx->bcc ^ rx->residue) & 0x00ff]; *(rx->nxt->b_wptr)++ = rx->residue; stats->rx_bytes++; rx->residue >>= 8; rx->rbits -= 8; rx->bytes++; if (!(s->option.popt & SS7_POPT_XSN)) { if (rx->bytes > s->config.m + 1 + 3) goto frame_too_long; } else { if (rx->bytes > s->config.m + 1 + 6) goto frame_too_long; } } } else { uint li; if (rx->rbits != 16) goto residue_error; if (rx->bcc != (rx->residue & 0xffff)) goto crc_error; if (!(s->option.popt & SS7_POPT_XSN)) { if (rx->bytes < 3) goto frame_too_short; sdt_rx_linkb(rx); li = (rx->msg->b_rptr[2] & 0x3f) + 3; if (rx->bytes != li && (li != 0x3f + 3 || rx->bytes < li)) goto length_error; } else { if (rx->bytes < 6) goto frame_too_short; sdt_rx_linkb(rx); li = (((rx->msg->b_rptr[5] << 8) | rx->msg->b_rptr[4]) & 0x1ff) + 6; if (rx->bytes != li && (li != 0x1ff + 6 || rx->bytes < li)) goto length_error; } stats->rx_sus++; sdt_daedr_received_bits(q, s, xchg(&rx->msg, NULL)); new_frame: rx->mode = RX_MODE_SYNC; if (r->sync) { begin_frame: if (r->bit_length) { rx->mode = RX_MODE_MOF; rx->residue = r->bit_string; rx->rbits = r->bit_length; rx->bytes = 0; rx->bcc = 0x00ff; } } } break; frame_too_long: stats->rx_frame_too_long++; stats->rx_frame_errors++; goto abort_frame; buffer_overflow: stats->rx_buffer_overflows++; goto abort_frame; aborted: stats->rx_aborts++; stats->rx_frame_errors++; goto abort_frame; length_error: stats->rx_length_error++; goto abort_frame; frame_too_short: stats->rx_frame_too_short++; stats->rx_frame_errors++; goto abort_frame; crc_error: stats->rx_crc_errors++; goto abort_frame; residue_error: stats->rx_residue_errors++; stats->rx_frame_errors++; goto abort_frame; abort_frame: if (rx->nxt) freemsg(xchg(&rx->nxt, NULL)); if (rx->msg) freemsg(xchg(&rx->msg, NULL)); stats->rx_sus_in_error++; sdt_daedr_su_in_error(q, s); if (r->flag) goto new_frame; rx->mode = RX_MODE_HUNT; stats->rx_sync_transitions++; s->rx_octets = 0; break; case RX_MODE_SYNC: if (!r->hunt && !r->idle) goto begin_frame; rx->mode = RX_MODE_HUNT; stats->rx_sync_transitions++; s->rx_octets = 0; break; case RX_MODE_HUNT: if (!r->flag) { if ((++(s->rx_octets)) >= s->config.N) { stats->rx_sus_in_error++; sdt_daedr_su_in_error(q, s); s->rx_octets -= s->config.N; } stats->rx_bits_octet_counted += 8; break; } stats->rx_sync_transitions++; goto new_frame; default: swerr(); goto abort_frame; } } } /* * ------------------------------------------------------------------------- * * Table allocation and generation * * ------------------------------------------------------------------------- * All Soft HDLC lookup stables are generated at module load time. This * permits the tables to be page-aligned in kernel memory for maximum cache * performance. */ /* * BC (Block Check) CRC Table Entries: * ----------------------------------- * RC tables perform CRC calculation on received bits after zero deletion and * delimitation. */ STATIC bc_entry_t bc_table_value(int bit_string, int bit_length) { int pos; for (pos = 0; pos < bit_length; pos++) { if (bit_string & 0x1) bit_string = (bit_string >> 1) ^ 0x8408; else bit_string >>= 1; } return (bit_string); } /* * TX (Transmission) Table Entries: * ----------------------------------- * TX table performs zero insertion on frame and CRC bit streams. */ STATIC tx_entry_t tx_table_valueN(int state, uint8_t byte, int len) { tx_entry_t result = { 0, }; int bit_mask = 1; result.state = state; result.bit_length = 0; while (len--) { if (byte & 0x1) { result.bit_string |= bit_mask; if (result.state++ == 4) { result.state = 0; result.bit_length++; bit_mask <<= 1; } } else result.state = 0; bit_mask <<= 1; byte >>= 1; } return result; } STATIC tx_entry_t tx_table_value(int state, uint8_t byte) { return tx_table_valueN(state, byte, 8); } /* * RX (Receive) Table Entries: * ----------------------------------- * RX table performs zero deletion, flag and abort detection, BOF and EOF * detection and residue on received bit streams. */ STATIC rx_entry_t rx_table_valueN(int state, uint8_t byte, int len) { rx_entry_t result = { 0, }; int bit_mask = 1; result.state = state; while (len--) { switch (result.state) { case 0: /* */ if (result.flag && !result.sync) { bit_mask = 1; result.bit_string = 0; result.bit_length = 0; result.sync = 1; } if (byte & 0x1) { result.state = 8; } else { result.state = 1; } break; case 1: /* 0 */ if (byte & 0x1) { result.state = 2; } else { bit_mask <<= 1; result.bit_length += 1; result.state = 1; } break; case 2: /* 01 */ if (byte & 0x1) { result.state = 3; } else { bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_length += 2; result.state = 1; } break; case 3: /* 011 */ if (byte & 0x1) { result.state = 4; } else { bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_length += 3; result.state = 1; } break; case 4: /* 0111 */ if (byte & 0x1) { result.state = 5; } else { bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_length += 4; result.state = 1; } break; case 5: /* 01111 */ if (byte & 0x1) { result.state = 6; } else { bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_length += 5; result.state = 1; } break; case 6: /* 011111 */ if (byte & 0x1) { result.state = 7; } else { bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_length += 6; result.state = 0; } break; case 7: /* 0111111 */ if (byte & 0x1) { result.sync = 0; result.flag = 0; result.hunt = 1; result.state = 12; } else { result.sync = 0; result.flag = 1; result.hunt = 0; result.idle = 0; result.state = 0; } break; case 8: /* 1 */ if (byte & 0x1) { result.state = 9; } else { result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_length += 1; result.state = 1; } break; case 9: /* 11 */ if (byte & 0x1) { result.state = 10; } else { result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_length += 2; result.state = 1; } break; case 10: /* 111 */ if (byte & 0x1) { result.state = 11; } else { result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_length += 3; result.state = 1; } break; case 11: /* 1111 */ if (byte & 0x1) { result.state = 12; } else { result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_length += 4; result.state = 1; } break; case 12: /* 11111 */ if (byte & 0x1) { result.state = 13; } else { result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_string |= bit_mask; bit_mask <<= 1; result.bit_length += 5; result.state = 0; } break; case 13: /* 111111 */ if (byte & 0x1) { result.hunt = 1; result.sync = 0; result.idle = 1; result.flag = 0; result.state = 12; } else { result.sync = 0; result.hunt = 0; result.idle = 0; result.flag = 1; result.state = 0; } break; } byte >>= 1; } return result; } STATIC rx_entry_t rx_table_value(int state, uint8_t byte) { return rx_table_valueN(state, byte, 8); } /* * TX (Transmit) Table: * ----------------------------------- * There is one TX table for 8-bit (octet) output values. The table has 256 * entries and is used to perform, for one sample, zero insertion on frame * bits for the transmitted bitstream. It is the reponsiblity of the SDL * driver to perform 8-bit to 7-bit conversion to DS0A. */ STATIC void tx_table_generate(void) { int j, k; for (j = 0; j < SDT_TX_STATES; j++) for (k = 0; k < 256; k++) *tx_index8(j, k) = tx_table_value(j, k); } /* * RX (Received) Tables: * ----------------------------------- * There is one RX table for 8 bit (octet) values. The table has 256 entries * and is used to perform, for one sample, zero deletion, abort detection, * flag detection and residue calculation on the received bitstream. The SDL * driver is responsible for performing 7-bit to 8-bit conversion before * delivering bits to the SDT. */ STATIC void rx_table_generate(void) { int j, k; for (j = 0; j < SDT_RX_STATES; j++) for (k = 0; k < 256; k++) *rx_index8(j, k) = rx_table_value(j, k); } /* * BC (CRC) Tables: * ----------------------------------- * CRC table organization: This is a CRC table which contains lookups for * all bit lengths less than or equal to 8. There are 512 entries. The * first 256 entries are for 8-bit bit lengths, the next 128 entries are for * 7-bit bit lengths, the next 64 entries for 6-bit bit lengths, etc. */ STATIC void bc_table_generate(void) { int pos = 0, bit_string, bit_length = 8, bit_mask = 0x100; do { for (bit_string = 0; bit_string < bit_mask; bit_string++, pos++) bc_table[pos] = bc_table_value(bit_string, bit_length); bit_length--; } while ((bit_mask >>= 1)); } /* * Table allocation * ------------------------------------------------------------------------- */ STATIC int sdt_init_tables(void) { size_t length; length = SDT_CRC_TABLE_LENGTH * sizeof(bc_entry_t); for (bc_order = 0; PAGE_SIZE << bc_order < length; bc_order++) ; if (!(bc_table = (bc_entry_t *) __get_free_pages(GFP_KERNEL, bc_order))) { cmn_err(CE_PANIC, "%s: Cannot allocate bc_table\n", __FUNCTION__); goto bc_failed; } printd(("sdt: allocated BC table size %u kernel pages\n", 1 << bc_order)); bc_table_generate(); printd(("sdt: generated BC table\n")); length = SDT_TX_TABLE_LENGTH * sizeof(tx_entry_t); for (tx_order = 0; PAGE_SIZE << tx_order < length; tx_order++) ; if (!(tx_table = (tx_entry_t *) __get_free_pages(GFP_KERNEL, tx_order))) { cmn_err(CE_PANIC, "%s: Cannot allocate tx_table\n", __FUNCTION__); goto tx_failed; } printd(("sdt: allocated Tx table size %u kernel pages\n", 1 << tx_order)); tx_table_generate(); printd(("sdt: generated 8-bit Tx table\n")); length = SDT_RX_TABLE_LENGTH * sizeof(rx_entry_t); for (rx_order = 0; PAGE_SIZE << rx_order < length; rx_order++) ; if (!(rx_table = (rx_entry_t *) __get_free_pages(GFP_KERNEL, rx_order))) { cmn_err(CE_PANIC, "%s: Cannot allocate rx_table\n", __FUNCTION__); goto rx_failed; } printd(("sdt: allocated Rx table size %u kernel pages\n", 1 << rx_order)); rx_table_generate(); printd(("sdt: generated 8-bit Rx table\n")); return (0); rx_failed: free_pages((unsigned long) tx_table, tx_order); tx_order = 0; tx_failed: free_pages((unsigned long) bc_table, bc_order); bc_order = 0; bc_failed: return (-ENOMEM); } STATIC void sdt_free_tables(void) { free_pages((unsigned long) bc_table, bc_order); printd(("sdt: freed BC table kernel pages\n")); free_pages((unsigned long) tx_table, tx_order); printd(("sdt: freed Tx table kernel pages\n")); free_pages((unsigned long) rx_table, rx_order); printd(("sdt: freed Rx table kernel pages\n")); } /* * ======================================================================== * * EVENTS * * ======================================================================== */ /* * RX WAKEUP * ----------------------------------- * This is called before the queue service routine unlocks the queue. We * must check if back-enabling has occured on an empty read queue. */ STATIC void sdt_rx_wakeup(queue_t *q) { (void) q; return; } /* * TX WAKEUP * ----------------------------------- * This is called before the queue service routine unlocks the queue. * sdt_tx_block will pull data from the queue as necessary. */ STATIC void sdt_tx_wakeup(queue_t *q) { struct sdt *s = SDT_PRIV(q); if ((s->i_state == LMI_ENABLED) && (s->statem.daedt_state != SDT_STATE_IDLE)) sdt_tx_block(q, s); return; } /* * ------------------------------------------------------------------------- * * Timer Events * * ------------------------------------------------------------------------- */ /* * T8 TIMEOUT * ----------------------------------- */ STATIC int sdt_t8_timeout(struct sdt *s) { queue_t *q = NULL; int err; if (s->statem.eim_state == SDT_STATE_MONITORING) { sdt_timer_start(s, t8); if (s->statem.su_received) { s->statem.su_received = 0; if (!s->statem.interval_error) { if ((s->statem.Ce -= s->config.De) < 0) s->statem.Ce = 0; return (QR_DONE); } } s->statem.Ce += s->config.Ue; if (s->statem.Ce > s->config.Te) { if ((err = sdt_lsc_link_failure_ind(q, s))) { s->statem.Ce -= s->config.Ue; return (err); } s->statem.eim_state = SDT_STATE_IDLE; } s->statem.interval_error = 0; } return (QR_DONE); } /* * ------------------------------------------------------------------------- * * LM User -> LM Provider Primitives * * ------------------------------------------------------------------------- */ /* * LMI_INFO_REQ: * ----------------------------------- * We just pass info request along and service them on reply from the lower * level. */ STATIC int sdt_info_req(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); lmi_info_req_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; return (QR_PASSFLOW); emsgsize: return lmi_error_ack(q, s, LMI_INFO_REQ, LMI_PROTOSHORT, EMSGSIZE); } /* * LMI_ATTACH_REQ: * ----------------------------------- * We do not perform attaches as this is a software SDT. The SDT selected is * the current SDT. We do, however, pass these along to the lower level if * the lower level is of the correct style. */ STATIC int sdt_attach_req(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); lmi_attach_req_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; if (s->i_state == LMI_UNUSABLE) goto eagain; if (s->i_style != LMI_STYLE2) goto eopnotsupp; if (s->i_state != LMI_UNATTACHED) goto outstate; if (mp->b_wptr < mp->b_rptr + sizeof(*p) + 2) goto badppa; s->i_state = LMI_ATTACH_PENDING; return (QR_PASSFLOW); badppa: ptrace(("%s: %p: PROTO: bad ppa (too short)\n", SDT_MOD_NAME, s)); return lmi_error_ack(q, s, LMI_ATTACH_REQ, LMI_BADPPA, EMSGSIZE); outstate: ptrace(("%s: %p: PROTO: out of state\n", SDT_MOD_NAME, s)); return lmi_error_ack(q, s, LMI_ATTACH_REQ, LMI_OUTSTATE, EPROTO); eopnotsupp: ptrace(("%s: %p: PROTO: primitive not supported for style\n", SDT_MOD_NAME, s)); return lmi_error_ack(q, s, LMI_ATTACH_REQ, LMI_NOTSUPP, EOPNOTSUPP); eagain: ptrace(("%s: %p: INFO: waiting for streams to become usable\n", SDT_MOD_NAME, s)); return (-EAGAIN); emsgsize: ptrace(("%s: %p: PROTO: M_PROTO block too short\n", SDT_MOD_NAME, s)); return lmi_error_ack(q, s, LMI_ATTACH_REQ, LMI_PROTOSHORT, EMSGSIZE); } /* * LMI_DETACH_REQ: * ----------------------------------- * We do not perform detaches as this is a software SDT. The SDT selected is * the current SDT. We do, however, pass these along to the lower level if * the lower level is of the correct style. */ STATIC int sdt_detach_req(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); lmi_detach_req_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; if (s->i_state == LMI_UNUSABLE) goto eagain; if (s->i_style != LMI_STYLE2) goto eopnotsupp; if (s->i_state != LMI_DISABLED) goto outstate; s->i_state = LMI_DETACH_PENDING; return (QR_PASSFLOW); outstate: ptrace(("%s: %p: PROTO: out of state\n", SDT_MOD_NAME, s)); return lmi_error_ack(q, s, LMI_DETACH_REQ, LMI_OUTSTATE, EPROTO); eopnotsupp: ptrace(("%s: %p: PROTO: primitive not supported for style\n", SDT_MOD_NAME, s)); return lmi_error_ack(q, s, LMI_DETACH_REQ, LMI_NOTSUPP, EOPNOTSUPP); eagain: ptrace(("%s: %p: INFO: waiting for streams to become usable\n", SDT_MOD_NAME, s)); return (-EAGAIN); emsgsize: ptrace(("%s: %p: PROTO: M_PROTO block too short\n", SDT_MOD_NAME, s)); return lmi_error_ack(q, s, LMI_DETACH_REQ, LMI_PROTOSHORT, EMSGSIZE); } /* * LMI_ENABLE_REQ: * ----------------------------------- * We must allow the SDL first crack at enabling before we fully enable. We * commit the enable when the LMI_ENABLE_CON is returned from below. */ STATIC int sdt_enable_req(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); lmi_enable_req_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; if (s->i_state == LMI_UNUSABLE) goto eagain; if (s->i_state != LMI_DISABLED) goto outstate; s->i_state = LMI_ENABLE_PENDING; return (QR_PASSFLOW); outstate: ptrace(("%s: %p: PROTO: out of state\n", SDT_MOD_NAME, s)); return lmi_error_ack(q, s, LMI_ENABLE_REQ, LMI_OUTSTATE, EPROTO); eagain: ptrace(("%s: %p: INFO: waiting for streams to become usable\n", SDT_MOD_NAME, s)); return (-EAGAIN); emsgsize: ptrace(("%s: %p: PROTO: M_PROTO block too short\n", SDT_MOD_NAME, s)); return lmi_error_ack(q, s, LMI_ENABLE_REQ, LMI_PROTOSHORT, EMSGSIZE); } /* * LMI_DISABLE_REQ: * ----------------------------------- * We must allow the SDL first carack an disabling before we fully disable. * We commit the disable when the LMI_DISABLE_CON is returned from below. */ STATIC int sdt_disable_req(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); lmi_disable_req_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; if (s->i_state == LMI_UNUSABLE) goto eagain; if (s->i_state != LMI_ENABLED) goto outstate; s->i_state = LMI_DISABLE_PENDING; return (QR_PASSFLOW); outstate: ptrace(("%s: %p: PROTO: out of state\n", SDT_MOD_NAME, s)); return lmi_error_ack(q, s, LMI_DISABLE_REQ, LMI_OUTSTATE, EPROTO); eagain: ptrace(("%s: %p: INFO: waiting for streams to become usable\n", SDT_MOD_NAME, s)); return (-EAGAIN); emsgsize: ptrace(("%s: %p: PROTO: M_PROTO block too short\n", SDT_MOD_NAME, s)); return lmi_error_ack(q, s, LMI_DISABLE_REQ, LMI_PROTOSHORT, EMSGSIZE); } /* * LMI_OPTMGMT_REQ: * ----------------------------------- */ STATIC int sdt_optmgmt_req(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); lmi_optmgmt_req_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; return (QR_PASSFLOW); emsgsize: (void) s; ptrace(("%s: %p: PROTO: M_PROTO block too short\n", SDT_MOD_NAME, s)); return lmi_error_ack(q, s, LMI_OPTMGMT_REQ, LMI_PROTOSHORT, EMSGSIZE); } /* * ------------------------------------------------------------------------- * * SDT User -> SDT Provider Primitives * * ------------------------------------------------------------------------- */ /* * M_DATA * ----------------------------------- */ STATIC int sdt_send_data(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); int len, hlen; if (s->i_state != LMI_ENABLED) goto discard; if (s->statem.daedt_state == SDT_STATE_IDLE) goto discard; /* ignore tramsmissions when daedt shut down */ len = msgdsize(mp); hlen = (s->option.popt & SS7_POPT_XSN) ? 6 : 3; if (len < hlen || len > hlen + s->config.m + 1) goto eproto; /* let tx_wakeup pull from the queue */ return (-EAGAIN); eproto: swerr(); /* length violation, error out stream */ return m_error(q, s, EPROTO); discard: return (QR_DONE); /* silent discard */ } /* * SDT_DAEDT_TRANSMISSION_REQ: * ----------------------------------- * This is the non-preferred way of sending data. It is preferred that * M_DATA blocks are used (above). We just strip off the M_PROTO and requeue * only the M_DATA blocks. */ STATIC int sdt_daedt_transmission_req(queue_t *q, mblk_t *mp) { mblk_t *dp; if ((dp = mp->b_cont) && dp->b_datap->db_type == M_DATA) { trace(); return (QR_STRIP); } return (-EPROTO); } /* * SDT_DAEDT_START_REQ: * ----------------------------------- */ STATIC int sdt_daedt_start_req(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); sdt_daedt_start_req_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; if (s->i_state != LMI_ENABLED) goto outstate; if (s->statem.daedt_state == SDT_STATE_IDLE) s->statem.daedt_state = SDT_STATE_IN_SERVICE; return (QR_DONE); outstate: ptrace(("%s: %p: PROTO: out of state\n", SDT_MOD_NAME, s)); return m_error(q, s, EPROTO); emsgsize: ptrace(("%s: %p: PROTO: M_PROTO block too short\n", SDT_MOD_NAME, s)); return (-EMSGSIZE); } /* * SDT_DAEDR_START_REQ: * ----------------------------------- */ STATIC int sdt_daedr_start_req(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); sdt_daedr_start_req_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; if (s->i_state != LMI_ENABLED) goto outstate; if (s->statem.daedr_state == SDT_STATE_IDLE) s->statem.daedr_state = SDT_STATE_IN_SERVICE; return (QR_DONE); outstate: ptrace(("%s: %p: PROTO: out of state\n", SDT_MOD_NAME, s)); return m_error(q, s, EPROTO); emsgsize: ptrace(("%s: %p: PROTO: M_PROTO block too short\n", SDT_MOD_NAME, s)); return (-EMSGSIZE); } /* * SDT_AERM_START_REQ: * ----------------------------------- */ STATIC int sdt_aerm_start_req(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); sdt_aerm_start_req_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; if (s->i_state != LMI_ENABLED) goto outstate; if (s->statem.aerm_state != SDT_STATE_MONITORING) { s->statem.Ca = 0; s->statem.aborted_proving = 0; s->statem.aerm_state = SDT_STATE_MONITORING; } return (QR_DONE); outstate: ptrace(("%s: %p: PROTO: out of state\n", SDT_MOD_NAME, s)); return m_error(q, s, EPROTO); emsgsize: ptrace(("%s: %p: PROTO: M_PROTO block too short\n", SDT_MOD_NAME, s)); return (-EMSGSIZE); } /* * SDT_AERM_STOP_REQ: * ----------------------------------- */ STATIC int sdt_aerm_stop_req(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); sdt_aerm_stop_req_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; if (s->i_state != LMI_ENABLED) goto outstate; if (s->statem.aerm_state != SDT_STATE_IDLE) { s->statem.aerm_state = SDT_STATE_IDLE; s->statem.Ti = s->config.Tin; } return (QR_DONE); outstate: ptrace(("%s: %p: PROTO: out of state\n", SDT_MOD_NAME, s)); return m_error(q, s, EPROTO); emsgsize: ptrace(("%s: %p: PROTO: M_PROTO block too short\n", SDT_MOD_NAME, s)); return (-EMSGSIZE); } /* * SDT_AERM_SET_TI_TO_TIN_REQ: * ----------------------------------- */ STATIC int sdt_aerm_set_ti_to_tin_req(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); sdt_aerm_set_ti_to_tin_req_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; if (s->i_state != LMI_ENABLED) goto outstate; if (s->statem.aerm_state == SDT_STATE_IDLE) s->statem.Ti = s->config.Tin; return (QR_DONE); outstate: ptrace(("%s: %p: PROTO: out of state\n", SDT_MOD_NAME, s)); return m_error(q, s, EPROTO); emsgsize: ptrace(("%s: %p: PROTO: M_PROTO block too short\n", SDT_MOD_NAME, s)); return (-EMSGSIZE); } /* * SDT_AERM_SET_TI_TO_TIE_REQ: * ----------------------------------- */ STATIC int sdt_aerm_set_ti_to_tie_req(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); sdt_aerm_set_ti_to_tie_req_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; if (s->i_state != LMI_ENABLED) goto outstate; if (s->statem.aerm_state == SDT_STATE_IDLE) s->statem.Ti = s->config.Tie; return (QR_DONE); outstate: ptrace(("%s: %p: PROTO: out of state\n", SDT_MOD_NAME, s)); return m_error(q, s, EPROTO); emsgsize: ptrace(("%s: %p: PROTO: M_PROTO block too short\n", SDT_MOD_NAME, s)); return (-EMSGSIZE); } /* * SDT_SUERM_START_REQ: * ----------------------------------- */ STATIC int sdt_suerm_start_req(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); sdt_suerm_start_req_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; if (s->i_state != LMI_ENABLED) goto outstate; if (s->statem.suerm_state == SDT_STATE_IDLE) { if (s->option.popt & SS7_POPT_HSL) return sdt_eim_start(q, s); else return sdt_suerm_start(q, s); } return (QR_DONE); outstate: ptrace(("%s: %p: PROTO: out of state\n", SDT_MOD_NAME, s)); return m_error(q, s, EPROTO); emsgsize: ptrace(("%s: %p: PROTO: M_PROTO block too short\n", SDT_MOD_NAME, s)); return (-EMSGSIZE); } /* * SDT_SUERM_STOP_REQ: * ----------------------------------- */ STATIC int sdt_suerm_stop_req(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); sdt_suerm_stop_req_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; if (s->i_state != LMI_ENABLED) goto outstate; if (s->statem.suerm_state != SDT_STATE_IDLE) { sdt_eim_stop(q, s); sdt_suerm_stop(q, s); } return (QR_DONE); outstate: ptrace(("%s: %p: PROTO: out of state\n", SDT_MOD_NAME, s)); return m_error(q, s, EPROTO); emsgsize: ptrace(("%s: %p: PROTO: M_PROTO block too short\n", SDT_MOD_NAME, s)); return (-EMSGSIZE); } /* * ------------------------------------------------------------------------- * * SDL-Provider -> SDL-User Primitives * * ------------------------------------------------------------------------- */ /* * LMI_INFO_ACK * ----------------------------------- * There are two situations in which we get such a reply: first is when we * are initially pushed as a module over an SDL (in state LMI_UNUSABLE); * second is whenever we need to service an LMI_INFO_REQ. */ STATIC int sdl_info_ack(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); lmi_info_ack_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; { ulong state = s->i_state; s->i_state = p->lmi_state; s->i_style = p->lmi_ppa_style; switch (state) { case LMI_UNUSABLE: if (s->i_state == LMI_UNUSABLE) goto merror; return (QR_DONE); case LMI_UNATTACHED: case LMI_ATTACH_PENDING: case LMI_DETACH_PENDING: case LMI_DISABLED: case LMI_ENABLE_PENDING: case LMI_DISABLE_PENDING: case LMI_ENABLED: p->lmi_version = s->i_version; p->lmi_state = s->i_state; p->lmi_max_sdu = s->config.m + 1; p->lmi_min_sdu = 3; p->lmi_header_len = 0; break; default: goto outstate; } } printd(("%s: %p: <- LMI_INFO_ACK\n", SDT_MOD_NAME, s)); return (QR_PASSFLOW); outstate: swerr(); return (-EPROTO); merror: swerr(); return m_error(q, s, -EFAULT); emsgsize: swerr(); return (-EMSGSIZE); } /* * LMI_OK_ACK * ----------------------------------- */ STATIC int sdl_ok_ack(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); lmi_ok_ack_t *p = ((typeof(p)) mp->b_rptr); if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; switch (s->i_state) { case LMI_UNUSABLE: goto discard; case LMI_UNATTACHED: case LMI_DISABLED: case LMI_ENABLE_PENDING: case LMI_DISABLE_PENDING: case LMI_ENABLED: goto outstate; case LMI_ATTACH_PENDING: s->i_state = LMI_DISABLED; break; case LMI_DETACH_PENDING: s->i_state = LMI_UNATTACHED; break; default: goto discard; } printd(("%s: %p: <- LMI_ERROR_ACK\n", SDT_MOD_NAME, s)); return (QR_PASSFLOW); outstate: swerr(); return (-EPROTO); discard: swerr(); return (-EFAULT); emsgsize: swerr(); return (-EMSGSIZE); } /* * LMI_ERROR_ACK * ----------------------------------- */ STATIC int sdl_error_ack(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); lmi_error_ack_t *p = ((typeof(p)) mp->b_rptr); if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; switch (s->i_state) { case LMI_UNUSABLE: goto merror; case LMI_UNATTACHED: case LMI_DISABLED: case LMI_ENABLED: break; case LMI_ATTACH_PENDING: s->i_state = LMI_UNATTACHED; break; case LMI_DETACH_PENDING: s->i_state = LMI_DISABLED; break; case LMI_ENABLE_PENDING: s->i_state = LMI_DISABLED; break; case LMI_DISABLE_PENDING: s->i_state = LMI_ENABLED; break; default: goto discard; } printd(("%s: %p: <- LMI_ERROR_ACK\n", SDT_MOD_NAME, s)); return (QR_PASSFLOW); discard: swerr(); return (-EFAULT); merror: swerr(); return m_error(q, s, -EFAULT); emsgsize: swerr(); return (-EMSGSIZE); } /* * LMI_ENABLE_CON * ----------------------------------- */ STATIC int sdl_enable_con(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); lmi_enable_con_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; switch (s->i_state) { case LMI_ENABLED: goto discard; case LMI_ENABLE_PENDING: s->i_state = LMI_ENABLED; break; case LMI_DISABLE_PENDING: case LMI_DISABLED: case LMI_DETACH_PENDING: case LMI_UNATTACHED: case LMI_ATTACH_PENDING: case LMI_UNUSABLE: goto outstate; default: goto discard; } printd(("%s: %p: <- LMI_ENABLE_CON\n", SDT_MOD_NAME, s)); return (QR_PASSFLOW); outstate: swerr(); return (-EPROTO); discard: swerr(); return (QR_DONE); emsgsize: swerr(); return (-EMSGSIZE); } /* * LMI_DISABLE_CON * ----------------------------------- */ STATIC int sdl_disable_con(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); lmi_disable_con_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; switch (s->i_state) { case LMI_DISABLED: /* already disabled */ goto discard; case LMI_DISABLE_PENDING: s->i_state = LMI_DISABLED; break; case LMI_ENABLED: case LMI_ENABLE_PENDING: case LMI_DETACH_PENDING: case LMI_UNATTACHED: case LMI_ATTACH_PENDING: case LMI_UNUSABLE: goto outstate; default: goto discard; } { int flags; lis_spin_lock_irqsave(&s->lock, &flags); { ss7_unbufcall((str_t *) s); sdt_timer_stop(s, t8); if (s->tx.msg && s->tx.msg != s->tx.cmp) freemsg(xchg(&s->tx.msg, NULL)); if (s->tx.cmp) freemsg(xchg(&s->tx.cmp, NULL)); s->tx.mode = TX_MODE_IDLE; s->statem.daedt_state = SDT_STATE_IDLE; if (s->rx.msg) freemsg(xchg(&s->rx.msg, NULL)); if (s->rx.nxt) freemsg(xchg(&s->rx.nxt, NULL)); if (s->rx.cmp) freemsg(xchg(&s->rx.cmp, NULL)); s->rx.mode = RX_MODE_HUNT; s->statem.daedr_state = SDT_STATE_IDLE; } lis_spin_unlock_irqrestore(&s->lock, &flags); printd(("%s: %p: <- LMI_DISABLE_CON\n", SDT_MOD_NAME, s)); return (QR_PASSFLOW); } outstate: swerr(); return (-EPROTO); discard: swerr(); return (QR_DONE); emsgsize: swerr(); return (-EMSGSIZE); } /* * LMI_OPTMGMT_ACK * ----------------------------------- */ STATIC int sdl_optmgmt_ack(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); lmi_optmgmt_ack_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; if (s->i_state == LMI_UNUSABLE) goto discard; if (s->i_state != LMI_ENABLED) goto outstate; printd(("%s: %p: <- LMI_OPTMGMT_ACK\n", SDT_MOD_NAME, s)); return (QR_PASSFLOW); outstate: swerr(); return (-EPROTO); discard: swerr(); return (QR_DONE); emsgsize: swerr(); return (-EMSGSIZE); } /* * LMI_ERROR_IND * ----------------------------------- */ STATIC int sdl_error_ind(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); lmi_error_ind_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; if (s->i_state == LMI_UNUSABLE) goto discard; if (s->i_state != LMI_ENABLED) goto outstate; printd(("%s: %p: <- LMI_ERROR_IND\n", SDT_MOD_NAME, s)); return (QR_PASSFLOW); outstate: swerr(); return (-EPROTO); discard: swerr(); return (QR_DONE); emsgsize: swerr(); return (-EMSGSIZE); } /* * LMI_STATS_IND * ----------------------------------- */ STATIC int sdl_stats_ind(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); lmi_stats_ind_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; if (s->i_state == LMI_UNUSABLE) goto discard; if (s->i_state != LMI_ENABLED) goto outstate; printd(("%s: %p: <- LMI_STATS_IND\n", SDT_MOD_NAME, s)); return (QR_PASSFLOW); outstate: swerr(); return (-EPROTO); discard: swerr(); return (QR_DONE); emsgsize: swerr(); return (-EMSGSIZE); } /* * LMI_EVENT_IND * ----------------------------------- */ STATIC int sdl_event_ind(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); lmi_event_ind_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; if (s->i_state == LMI_UNUSABLE) goto discard; if (s->i_state != LMI_ENABLED) goto outstate; printd(("%s: %p: <- LMI_EVENT_IND\n", SDT_MOD_NAME, s)); return (QR_PASSFLOW); outstate: swerr(); return (-EPROTO); discard: swerr(); return (QR_DONE); emsgsize: swerr(); return (-EMSGSIZE); } /* * M_DATA * ----------------------------------- */ STATIC int sdt_recv_data(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); int err; if (s->statem.daedr_state == SDT_STATE_IDLE) return (QR_DONE); /* discard */ if (canputnext(s->oq)) { sdt_rx_block(q, s, mp); if (s->statem.daedr_state == SDT_STATE_CONGESTED) if ((err = sdt_rc_no_congestion_ind(q, s)) >= 0) s->statem.daedr_state = SDT_STATE_IN_SERVICE; return (QR_DONE); } if (s->statem.daedr_state == SDT_STATE_IN_SERVICE) { if ((err = sdt_rc_congestion_accept_ind(q, s)) < 0) return (err); s->statem.daedr_state = SDT_STATE_CONGESTED; } return (-EBUSY); } /* * SDL_RECEIVED_BITS_IND * ----------------------------------- * This is the non-preferred way of receiving data. It is preffered that * M_DATA blocks are used (above). We just strip off the M_PROTO and requeue * only the M_DATA blocks. */ STATIC int sdl_received_bits_ind(queue_t *q, mblk_t *mp) { mblk_t *dp; if ((dp = mp->b_cont) && dp->b_datap->db_type == M_DATA) { trace(); return (QR_STRIP); } return (-EPROTO); } /* * SDL_DISCONNECT_IND * ----------------------------------- */ STATIC int sdl_disconnect_ind(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); int err; sdl_disconnect_ind_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto emsgsize; if (s->i_state != LMI_ENABLED) goto outstate; if (s->statem.daedr_state == SDT_STATE_IDLE) goto discard; if (s->statem.daedt_state == SDT_STATE_IDLE) goto discard; if (s->statem.suerm_state == SDT_STATE_IN_SERVICE) { if ((err = sdt_lsc_link_failure_ind(q, s)) == QR_DONE) { s->statem.suerm_state = SDT_STATE_IDLE; return (QR_DONE); } return (err); } if (s->statem.aerm_state == SDT_STATE_MONITORING) { if ((err = sdt_iac_abort_proving_ind(q, s)) == QR_DONE) { s->statem.aerm_state = SDT_STATE_IDLE; return (QR_DONE); } return (err); } swerr(); return (-EFAULT); discard: swerr(); return (QR_DONE); outstate: swerr(); return (-EPROTO); emsgsize: swerr(); return (-EMSGSIZE); } /* * ========================================================================= * * IO Controls * * ========================================================================= * * LM IO Controls * * ------------------------------------------------------------------------- */ STATIC int lmi_test_config(struct sdt *sdt, lmi_config_t * arg) { return (-EOPNOTSUPP); } STATIC int lmi_commit_config(struct sdt *sdt, lmi_config_t * arg) { return (-EOPNOTSUPP); } STATIC int lmi_iocgoptions(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); int flags, ret = 0; lmi_option_t *arg = (typeof(arg)) mp->b_cont->b_rptr; lis_spin_lock_irqsave(&s->lock, &flags); { *arg = s->option; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (ret); } rare(); return (-EINVAL); } STATIC int lmi_iocsoptions(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); int flags, ret = 0; lmi_option_t *arg = (typeof(arg)) mp->b_cont->b_rptr; lis_spin_lock_irqsave(&s->lock, &flags); { s->option = *arg; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (ret); } rare(); return (-EINVAL); } STATIC int lmi_iocgconfig(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); int flags = 0; lmi_config_t *arg = (typeof(arg)) mp->b_cont->b_rptr; lis_spin_lock_irqsave(&s->lock, &flags); { arg->version = s->i_version; arg->style = s->i_style; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (0); } rare(); return (-EINVAL); } STATIC int lmi_iocsconfig(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); int flags = 0; lmi_config_t *arg = (typeof(arg)) mp->b_cont->b_rptr; lis_spin_lock_irqsave(&s->lock, &flags); { s->i_version = arg->version; s->i_style = arg->style; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (0); } rare(); return (-EINVAL); } STATIC int lmi_ioctconfig(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); lmi_config_t *arg = (typeof(arg)) mp->b_cont->b_rptr; return lmi_test_config(s, arg); } rare(); return (-EINVAL); } STATIC int lmi_ioccconfig(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); lmi_config_t *arg = (typeof(arg)) mp->b_cont->b_rptr; return lmi_commit_config(s, arg); } rare(); return (-EINVAL); } STATIC int lmi_iocgstatem(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); int flags = 0; lmi_statem_t *arg = (typeof(arg)) mp->b_cont->b_rptr; lis_spin_lock_irqsave(&s->lock, &flags); { arg->state = s->i_state; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (0); } rare(); return (-EINVAL); } STATIC int lmi_ioccmreset(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); lmi_statem_t *arg = (typeof(arg)) mp->b_cont->b_rptr; int flags, ret = 0; lis_spin_lock_irqsave(&s->lock, &flags); { s->i_state = LMI_UNUSABLE; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (ret); } rare(); return (-EINVAL); } STATIC int lmi_iocgstatsp(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); lmi_sta_t *arg = (typeof(arg)) mp->b_cont->b_rptr; int flags, ret = 0; lis_spin_lock_irqsave(&s->lock, &flags); { *arg = s->statsp; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (ret); } rare(); return (-EINVAL); } STATIC int lmi_iocsstatsp(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); lmi_sta_t *arg = (typeof(arg)) mp->b_cont->b_rptr; int flags, ret = 0; lis_spin_lock_irqsave(&s->lock, &flags); { s->statsp = *arg; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (ret); } rare(); return (-EINVAL); } STATIC int lmi_iocgstats(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); lmi_stats_t *arg = (typeof(arg)) mp->b_cont->b_rptr; int flags, ret; lis_spin_lock_irqsave(&s->lock, &flags); { ret = -EOPNOTSUPP; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (ret); } rare(); return (-EINVAL); } STATIC int lmi_ioccstats(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); int flags, ret; (void) mp; lis_spin_lock_irqsave(&s->lock, &flags); { ret = -EOPNOTSUPP; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (ret); } STATIC int lmi_iocgnotify(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); lmi_notify_t *arg = (typeof(arg)) mp->b_cont->b_rptr; int flags, ret; lis_spin_lock_irqsave(&s->lock, &flags); { ret = -EOPNOTSUPP; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (ret); } rare(); return (-EINVAL); } STATIC int lmi_iocsnotify(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); lmi_notify_t *arg = (typeof(arg)) mp->b_cont->b_rptr; int flags, ret; lis_spin_lock_irqsave(&s->lock, &flags); { ret = -EOPNOTSUPP; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (ret); } rare(); return (-EINVAL); } STATIC int lmi_ioccnotify(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); lmi_notify_t *arg = (typeof(arg)) mp->b_cont->b_rptr; int flags, ret; lis_spin_lock_irqsave(&s->lock, &flags); { ret = -EOPNOTSUPP; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (ret); } rare(); return (-EINVAL); } /* * ------------------------------------------------------------------------- * * SDT IO Controls * * ------------------------------------------------------------------------- */ STATIC int sdt_test_config(struct sdt *s, sdt_config_t * arg) { int ret = 0; int flags = 0; lis_spin_lock_irqsave(&s->lock, &flags); do { if (!arg->t8) arg->t8 = s->config.t8; if (!arg->Tin) arg->Tin = s->config.Tin; if (!arg->Tie) arg->Tie = s->config.Tie; if (!arg->T) arg->T = s->config.T; if (!arg->D) arg->D = s->config.D; if (!arg->Te) arg->Te = s->config.Te; if (!arg->De) arg->De = s->config.De; if (!arg->Ue) arg->Ue = s->config.Ue; if (!arg->N) arg->N = s->config.N; if (!arg->m) arg->m = s->config.m; if (!arg->b) arg->b = s->config.b; else if (arg->b != s->config.b) { ret = -EINVAL; break; } } while (0); lis_spin_unlock_irqrestore(&s->lock, &flags); return (ret); } STATIC int sdt_commit_config(struct sdt *s, sdt_config_t * arg) { int flags = 0; lis_spin_lock_irqsave(&s->lock, &flags); { sdt_test_config(s, arg); s->config = *arg; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (0); } STATIC int sdt_iocgoptions(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); int flags = 0; lmi_option_t *arg = (typeof(arg)) mp->b_cont->b_rptr; lis_spin_lock_irqsave(&s->lock, &flags); { *arg = s->option; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (0); } rare(); return (-EINVAL); } STATIC int sdt_iocsoptions(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); int flags = 0; lmi_option_t *arg = (typeof(arg)) mp->b_cont->b_rptr; lis_spin_lock_irqsave(&s->lock, &flags); { s->option = *arg; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (0); } rare(); return (-EINVAL); } STATIC int sdt_iocgconfig(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); int flags = 0; sdt_config_t *arg = (typeof(arg)) mp->b_cont->b_rptr; lis_spin_lock_irqsave(&s->lock, &flags); { *arg = s->config; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (0); } rare(); return (-EINVAL); } STATIC int sdt_iocsconfig(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); int flags = 0; sdt_config_t *arg = (typeof(arg)) mp->b_cont->b_rptr; lis_spin_lock_irqsave(&s->lock, &flags); { s->config = *arg; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (0); } rare(); return (-EINVAL); } STATIC int sdt_ioctconfig(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); sdt_config_t *arg = (typeof(arg)) mp->b_cont->b_rptr; return sdt_test_config(s, arg); } rare(); return (-EINVAL); } STATIC int sdt_ioccconfig(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); sdt_config_t *arg = (typeof(arg)) mp->b_cont->b_rptr; return sdt_commit_config(s, arg); } rare(); return (-EINVAL); } STATIC int sdt_iocgstatem(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); int flags = 0; sdt_statem_t *arg = (typeof(arg)) mp->b_cont->b_rptr; lis_spin_lock_irqsave(&s->lock, &flags); { *arg = s->statem; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (0); } rare(); return (-EINVAL); } STATIC int sdt_ioccmreset(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); (void) s; (void) mp; fixme(("%s: Master reset\n", SDT_MOD_NAME)); return (-EOPNOTSUPP); } STATIC int sdt_iocgstatsp(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); int flags = 0; lmi_sta_t *arg = (typeof(arg)) mp->b_cont->b_rptr; lis_spin_lock_irqsave(&s->lock, &flags); { *arg = s->statsp; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (0); } rare(); return (-EINVAL); } STATIC int sdt_iocsstatsp(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); int flags = 0; lmi_sta_t *arg = (typeof(arg)) mp->b_cont->b_rptr; lis_spin_lock_irqsave(&s->lock, &flags); { s->statsp = *arg; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (0); } rare(); return (-EINVAL); } STATIC int sdt_iocgstats(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); int flags = 0; sdt_stats_t *arg = (typeof(arg)) mp->b_cont->b_rptr; lis_spin_lock_irqsave(&s->lock, &flags); { *arg = s->stats; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (0); } rare(); return (-EINVAL); } STATIC int sdt_ioccstats(queue_t *q, mblk_t *mp) { int flags = 0; struct sdt *s = SDT_PRIV(q); (void) mp; lis_spin_lock_irqsave(&s->lock, &flags); { bzero(&s->stats, sizeof(s->stats)); } lis_spin_unlock_irqrestore(&s->lock, &flags); return (0); } STATIC int sdt_iocgnotify(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); int flags = 0; sdt_notify_t *arg = (typeof(arg)) mp->b_cont->b_rptr; lis_spin_lock_irqsave(&s->lock, &flags); { *arg = s->notify; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (0); } rare(); return (-EINVAL); } STATIC int sdt_iocsnotify(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); int flags = 0; sdt_notify_t *arg = (typeof(arg)) mp->b_cont->b_rptr; lis_spin_lock_irqsave(&s->lock, &flags); { s->notify = *arg; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (0); } rare(); return (-EINVAL); } STATIC int sdt_ioccnotify(queue_t *q, mblk_t *mp) { if (mp->b_cont) { struct sdt *s = SDT_PRIV(q); int flags = 0; sdt_notify_t *arg = (typeof(arg)) mp->b_cont->b_rptr; lis_spin_lock_irqsave(&s->lock, &flags); { s->notify.events &= ~arg->events; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (0); } rare(); return (-EINVAL); } STATIC int sdt_ioccabort(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); int ret, flags = 0; (void) mp; lis_spin_lock_irqsave(&s->lock, &flags); { ret = -EOPNOTSUPP; } lis_spin_unlock_irqrestore(&s->lock, &flags); return (ret); } /* * ======================================================================== * * STREAMS Message Handling * * ======================================================================== * * M_IOCTL Handling * ----------------------------------------------------------------------- */ STATIC int sdt_w_ioctl(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); 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 type = _IOC_TYPE(cmd), nr = _IOC_NR(cmd), size = _IOC_SIZE(cmd); struct linkblk *lp = (struct linkblk *) arg; int ret = 0; switch (type) { case __SID: { switch (nr) { case _IOC_NR(I_STR): case _IOC_NR(I_LINK): case _IOC_NR(I_PLINK): case _IOC_NR(I_UNLINK): case _IOC_NR(I_PUNLINK): (void) lp; ptrace(("%s: %p: ERROR: Unsupported STREAMS ioctl %d\n", SDT_MOD_NAME, s, nr)); ret = (-EINVAL); break; default: ptrace(("%s: %p: ERROR: Unsupported STREAMS ioctl %d\n", SDT_MOD_NAME, s, nr)); ret = (-EOPNOTSUPP); break; } break; } case LMI_IOC_MAGIC: { if (count < size || s->i_state == LMI_UNATTACHED) { ret = (-EINVAL); break; } switch (nr) { case _IOC_NR(LMI_IOCGOPTIONS): /* lmi_option_t */ ret = lmi_iocgoptions(q, mp); break; case _IOC_NR(LMI_IOCSOPTIONS): /* lmi_option_t */ ret = lmi_iocsoptions(q, mp); break; case _IOC_NR(LMI_IOCGCONFIG): /* lmi_config_t */ ret = lmi_iocgconfig(q, mp); break; case _IOC_NR(LMI_IOCSCONFIG): /* lmi_config_t */ ret = lmi_iocsconfig(q, mp); break; case _IOC_NR(LMI_IOCTCONFIG): /* lmi_config_t */ ret = lmi_ioctconfig(q, mp); break; case _IOC_NR(LMI_IOCCCONFIG): /* lmi_config_t */ ret = lmi_ioccconfig(q, mp); break; case _IOC_NR(LMI_IOCGSTATEM): /* lmi_statem_t */ ret = lmi_iocgstatem(q, mp); break; case _IOC_NR(LMI_IOCCMRESET): /* lmi_statem_t */ ret = lmi_ioccmreset(q, mp); break; case _IOC_NR(LMI_IOCGSTATSP): /* lmi_sta_t */ ret = lmi_iocgstatsp(q, mp); break; case _IOC_NR(LMI_IOCSSTATSP): /* lmi_sta_t */ ret = lmi_iocsstatsp(q, mp); break; case _IOC_NR(LMI_IOCGSTATS): /* lmi_stats_t */ ret = lmi_iocgstats(q, mp); break; case _IOC_NR(LMI_IOCCSTATS): /* lmi_stats_t */ ret = lmi_ioccstats(q, mp); break; case _IOC_NR(LMI_IOCGNOTIFY): /* lmi_notify_t */ ret = lmi_iocgnotify(q, mp); break; case _IOC_NR(LMI_IOCSNOTIFY): /* lmi_notify_t */ ret = lmi_iocsnotify(q, mp); break; case _IOC_NR(LMI_IOCCNOTIFY): /* lmi_notify_t */ ret = lmi_ioccnotify(q, mp); break; default: ptrace(("%s: %p: ERROR: Unsupported SDT ioctl %d\n", SDT_MOD_NAME, s, nr)); ret = -EOPNOTSUPP; break; } break; } case SDT_IOC_MAGIC: { if (count < size || s->i_state == LMI_UNATTACHED) { ret = (-EINVAL); break; } switch (nr) { case _IOC_NR(SDT_IOCGOPTIONS): /* lmi_option_t */ ret = sdt_iocgoptions(q, mp); break; case _IOC_NR(SDT_IOCSOPTIONS): /* lmi_option_t */ ret = sdt_iocsoptions(q, mp); break; case _IOC_NR(SDT_IOCGCONFIG): /* sdt_config_t */ ret = sdt_iocgconfig(q, mp); break; case _IOC_NR(SDT_IOCSCONFIG): /* sdt_config_t */ ret = sdt_iocsconfig(q, mp); break; case _IOC_NR(SDT_IOCTCONFIG): /* sdt_config_t */ ret = sdt_ioctconfig(q, mp); break; case _IOC_NR(SDT_IOCCCONFIG): /* sdt_config_t */ ret = sdt_ioccconfig(q, mp); break; case _IOC_NR(SDT_IOCGSTATEM): /* sdt_statem_t */ ret = sdt_iocgstatem(q, mp); break; case _IOC_NR(SDT_IOCCMRESET): /* sdt_statem_t */ ret = sdt_ioccmreset(q, mp); break; case _IOC_NR(SDT_IOCGSTATSP): /* lmi_sta_t */ ret = sdt_iocgstatsp(q, mp); break; case _IOC_NR(SDT_IOCSSTATSP): /* lmi_sta_t */ ret = sdt_iocsstatsp(q, mp); break; case _IOC_NR(SDT_IOCGSTATS): /* sdt_stats_t */ ret = sdt_iocgstats(q, mp); break; case _IOC_NR(SDT_IOCCSTATS): /* sdt_stats_t */ ret = sdt_ioccstats(q, mp); break; case _IOC_NR(SDT_IOCGNOTIFY): /* sdt_notify_t */ ret = sdt_iocgnotify(q, mp); break; case _IOC_NR(SDT_IOCSNOTIFY): /* sdt_notify_t */ ret = sdt_iocsnotify(q, mp); break; case _IOC_NR(SDT_IOCCNOTIFY): /* sdt_notify_t */ ret = sdt_ioccnotify(q, mp); break; case _IOC_NR(SDT_IOCCABORT): /* */ ret = sdt_ioccabort(q, mp); break; default: ptrace(("%s: ERROR: Unsupported SDT ioctl %d\n", SDT_MOD_NAME, nr)); ret = -EOPNOTSUPP; break; } break; } default: ret = (QR_PASSFLOW); break; } if (ret > 0) { return (ret); } else 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 = -ret; iocp->ioc_rval = -1; } qreply(q, mp); return (QR_ABSORBED); } /* * ----------------------------------------------------------------------- * * M_PROTO, M_PCPROTO Handling * * ----------------------------------------------------------------------- */ /* * Primitives from User to SDT. * ----------------------------------- */ STATIC int sdt_w_proto(queue_t *q, mblk_t *mp) { int rtn; ulong prim; struct sdt *s = SDT_PRIV(q); ulong oldstate = s->i_state; if ((prim = *(ulong *) mp->b_rptr) == SDT_DAEDT_TRANSMISSION_REQ) { printd(("%s: %p: -> SDT_DAEDT_TRANSMISSION_REQ [%d]\n", SDT_MOD_NAME, s, msgdsize(mp->b_cont))); if ((rtn = sdt_daedt_transmission_req(q, mp)) < 0) s->i_state = oldstate; return (rtn); } switch (prim) { case SDT_DAEDT_TRANSMISSION_REQ: printd(("%s: %p: -> SDT_DAEDT_TRANSMISSION_REQ [%d]\n", SDT_MOD_NAME, s, msgdsize(mp->b_cont))); rtn = sdt_daedt_transmission_req(q, mp); break; case SDT_DAEDT_START_REQ: printd(("%s: %p: -> SDT_DAEDT_START_REQ\n", SDT_MOD_NAME, s)); rtn = sdt_daedt_start_req(q, mp); break; case SDT_DAEDR_START_REQ: printd(("%s: %p: -> SDT_DAEDT_START_REQ\n", SDT_MOD_NAME, s)); rtn = sdt_daedr_start_req(q, mp); break; case SDT_AERM_START_REQ: printd(("%s: %p: -> SDT_AERM_START_REQ\n", SDT_MOD_NAME, s)); rtn = sdt_aerm_start_req(q, mp); break; case SDT_AERM_STOP_REQ: printd(("%s: %p: -> SDT_AERM_STOP_REQ\n", SDT_MOD_NAME, s)); rtn = sdt_aerm_stop_req(q, mp); break; case SDT_AERM_SET_TI_TO_TIN_REQ: printd(("%s: %p: -> SDT_AERM_SET_TI_TO_TIN_REQ\n", SDT_MOD_NAME, s)); rtn = sdt_aerm_set_ti_to_tin_req(q, mp); break; case SDT_AERM_SET_TI_TO_TIE_REQ: printd(("%s: %p: -> SDT_AERM_SET_TI_TO_TIE_REQ\n", SDT_MOD_NAME, s)); rtn = sdt_aerm_set_ti_to_tie_req(q, mp); break; case SDT_SUERM_START_REQ: printd(("%s: %p: -> SDT_SUERM_START_REQ\n", SDT_MOD_NAME, s)); rtn = sdt_suerm_start_req(q, mp); break; case SDT_SUERM_STOP_REQ: printd(("%s: %p: -> SDT_SUERM_STOP_REQ\n", SDT_MOD_NAME, s)); rtn = sdt_suerm_stop_req(q, mp); break; case LMI_INFO_REQ: printd(("%s: %p: -> LMI_INFO_REQ\n", SDT_MOD_NAME, s)); rtn = sdt_info_req(q, mp); break; case LMI_ATTACH_REQ: printd(("%s: %p: -> LMI_ATTACH_REQ\n", SDT_MOD_NAME, s)); rtn = sdt_attach_req(q, mp); break; case LMI_DETACH_REQ: printd(("%s: %p: -> LMI_DETACH_REQ\n", SDT_MOD_NAME, s)); rtn = sdt_detach_req(q, mp); break; case LMI_ENABLE_REQ: printd(("%s: %p: -> LMI_ENABLE_REQ\n", SDT_MOD_NAME, s)); rtn = sdt_enable_req(q, mp); break; case LMI_DISABLE_REQ: printd(("%s: %p: -> LMI_DISABLE_REQ\n", SDT_MOD_NAME, s)); rtn = sdt_disable_req(q, mp); break; case LMI_OPTMGMT_REQ: printd(("%s: %p: -> LMI_OPTMGMT_REQ\n", SDT_MOD_NAME, s)); rtn = sdt_optmgmt_req(q, mp); break; default: swerr(); rtn = (-EOPNOTSUPP); break; } if (rtn < 0) s->i_state = oldstate; return (rtn); } /* * Primitives from SDL to SDT. * ----------------------------------- */ STATIC int sdt_r_proto(queue_t *q, mblk_t *mp) { int rtn; ulong prim; struct sdt *s = SDT_PRIV(q); ulong oldstate = s->i_state; /* Fast Path */ if ((prim = *(ulong *) mp->b_rptr) == SDL_RECEIVED_BITS_IND) { printd(("%s: %p: SDL_RECEIVED_BITS_IND [%d] <-\n", SDT_MOD_NAME, s, msgdsize(mp->b_cont))); if ((rtn = sdl_received_bits_ind(q, mp)) < 0) s->i_state = oldstate; return (rtn); } switch (prim) { case SDL_RECEIVED_BITS_IND: printd(("%s: %p: SDL_RECEIVED_BITS_IND [%d] <-\n", SDT_MOD_NAME, s, msgdsize(mp->b_cont))); rtn = sdl_received_bits_ind(q, mp); break; case SDL_DISCONNECT_IND: printd(("%s: %p: SDL_DISCONNECT_IND <-\n", SDT_MOD_NAME, s)); rtn = sdl_disconnect_ind(q, mp); break; case LMI_INFO_ACK: printd(("%s: %p: LMI_INFO_ACK <-\n", SDT_MOD_NAME, s)); rtn = sdl_info_ack(q, mp); break; case LMI_OK_ACK: printd(("%s: %p: LMI_OK_ACK <-\n", SDT_MOD_NAME, s)); rtn = sdl_ok_ack(q, mp); break; case LMI_ERROR_ACK: printd(("%s: %p: LMI_ERROR_ACK <-\n", SDT_MOD_NAME, s)); rtn = sdl_error_ack(q, mp); break; case LMI_ENABLE_CON: printd(("%s: %p: LMI_ENABLE_CON <-\n", SDT_MOD_NAME, s)); rtn = sdl_enable_con(q, mp); break; case LMI_DISABLE_CON: printd(("%s: %p: LMI_DISABLE_CON <-\n", SDT_MOD_NAME, s)); rtn = sdl_disable_con(q, mp); break; case LMI_OPTMGMT_ACK: printd(("%s: %p: LMI_OPTMGMT_ACK <-\n", SDT_MOD_NAME, s)); rtn = sdl_optmgmt_ack(q, mp); break; case LMI_ERROR_IND: printd(("%s: %p: LMI_ERROR_IND <-\n", SDT_MOD_NAME, s)); rtn = sdl_error_ind(q, mp); break; case LMI_STATS_IND: printd(("%s: %p: LMI_STATS_IND <-\n", SDT_MOD_NAME, s)); rtn = sdl_stats_ind(q, mp); break; case LMI_EVENT_IND: printd(("%s: %p: LMI_EVENT_IND <-\n", SDT_MOD_NAME, s)); rtn = sdl_event_ind(q, mp); break; default: swerr(); rtn = (-EOPNOTSUPP); break; } if (rtn < 0) s->i_state = oldstate; return (rtn); } /* * ------------------------------------------------------------------------- * * M_DATA Handling * * ------------------------------------------------------------------------- */ STATIC INLINE int sdt_w_data(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); (void) s; printd(("%s: %p: -> M_DATA [%d]\n", SDT_MOD_NAME, s, msgdsize(mp))); return sdt_send_data(q, mp); } STATIC INLINE int sdt_r_data(queue_t *q, mblk_t *mp) { struct sdt *s = SDT_PRIV(q); (void) s; printd(("%s: %p: M_DATA [%d] <-\n", SDT_MOD_NAME, s, msgdsize(mp))); return sdt_recv_data(q, mp); } /* * ========================================================================= * * PUT and SRV * * ========================================================================= */ STATIC INLINE int sdt_w_prim(queue_t *q, mblk_t *mp) { /* Fast Path */ if (mp->b_datap->db_type == M_DATA) return sdt_w_data(q, mp); switch (mp->b_datap->db_type) { case M_DATA: return sdt_w_data(q, mp); case M_PROTO: case M_PCPROTO: return sdt_w_proto(q, mp); case M_FLUSH: return ss7_w_flush(q, mp); case M_IOCTL: return sdt_w_ioctl(q, mp); } return (QR_PASSALONG); } STATIC INLINE int sdt_r_prim(queue_t *q, mblk_t *mp) { /* Fast Path */ if (mp->b_datap->db_type == M_DATA) return sdt_r_data(q, mp); switch (mp->b_datap->db_type) { case M_DATA: return sdt_r_data(q, mp); case M_PROTO: case M_PCPROTO: return sdt_r_proto(q, mp); case M_FLUSH: return ss7_r_flush(q, mp); } return (QR_PASSALONG); } /* * ======================================================================= * * OPEN and CLOSE * * ======================================================================= */ /* * OPEN * ----------------------------------------------------------------------- */ STATIC int sdt_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp) { int err; MOD_INC_USE_COUNT; /* keep module from unloading in our face */ if (q->q_ptr != NULL) { MOD_DEC_USE_COUNT; return (0); /* already open */ } if (sflag == MODOPEN || WR(q)->q_next != NULL) { int cmajor = getmajor(*devp); int cminor = getminor(*devp); struct sdt *s; /* test for multiple push */ for (s = sdt_opens; s; s = s->next) { if (s->u.dev.cmajor == cmajor && s->u.dev.cminor == cminor) { MOD_DEC_USE_COUNT; return (ENXIO); } } if (!(sdt_alloc_priv(q, &sdt_opens, devp, crp))) { MOD_DEC_USE_COUNT; return (ENOMEM); } /* generate immediate information request */ if ((err = sdl_info_req(q, s)) < 0) { sdt_free_priv(q); MOD_DEC_USE_COUNT; return (-err); } return (0); } MOD_DEC_USE_COUNT; return (EIO); } /* * CLOSED * ----------------------------------------------------------------------- */ STATIC int sdt_close(queue_t *q, int flag, cred_t *crp) { (void) flag; (void) crp; sdt_free_priv(q); MOD_DEC_USE_COUNT; return (0); } /* * ======================================================================== * * PRIVATE struct allocation, deallocation and cache * * ======================================================================== */ STATIC kmem_cache_t *sdt_priv_cachep = NULL; STATIC int sdt_init_caches(void) { if (!sdt_priv_cachep && !(sdt_priv_cachep = kmem_cache_create("sdt_priv_cachep", sizeof(struct sdt), 0, SLAB_HWCACHE_ALIGN, NULL, NULL))) { cmn_err(CE_PANIC, "%s: Cannot allocate sdt_priv_cachep", __FUNCTION__); return (-ENOMEM); } printd(("%s: Allocated/selected private structure cache\n", SDT_MOD_NAME)); return (0); } STATIC void sdt_free_caches(void) { if (sdt_priv_cachep) { if (kmem_cache_destroy(sdt_priv_cachep)) cmn_err(CE_WARN, "%s: did not destroy sdt_priv_cachep.", __FUNCTION__); else printd(("sdt: destroyed sdt_priv_cachep\n")); } return; } STATIC struct sdt *sdt_alloc_priv(queue_t *q, struct sdt **sp, dev_t *devp, cred_t *crp) { struct sdt *s; if ((s = kmem_cache_alloc(sdt_priv_cachep, SLAB_ATOMIC))) { printd(("sdt: allocated module private structure\n")); bzero(s, sizeof(*s)); sdt_get(s); /* first get */ s->u.dev.cmajor = getmajor(*devp); s->u.dev.cminor = getminor(*devp); s->cred = *crp; (s->oq = RD(q))->q_ptr = sdt_get(s); (s->iq = WR(q))->q_ptr = sdt_get(s); lis_spin_lock_init(&s->qlock, "sdt-queue-lock"); s->o_prim = &sdt_r_prim; s->i_prim = &sdt_w_prim; s->o_wakeup = &sdt_rx_wakeup; s->i_wakeup = &sdt_tx_wakeup; s->i_state = LMI_UNUSABLE; s->i_style = LMI_STYLE1; s->i_version = 1; lis_spin_lock_init(&s->qlock, "sdt-priv_lock"); if ((s->next = *sp)) s->next->prev = &s->next; s->prev = sp; *sp = sdt_get(s); printd(("%s: %p: linked module private structure\n", SDT_MOD_NAME, s)); /* configuration defaults */ s->option = lmi_default; s->config = sdt_default; printd(("%s: %p: setting module private structure defaults\n", SDT_MOD_NAME, s)); } else ptrace(("%s: ERROR: Could not allocate module private structure\n", SDT_MOD_NAME)); return (s); } STATIC void sdt_free_priv(queue_t *q) { struct sdt *s = SDT_PRIV(q); int flags = 0; ensure(s, return); lis_spin_lock_irqsave(&s->lock, &flags); { ss7_unbufcall((str_t *) s); sdt_timer_stop(s, tall); if (s->tx.msg && s->tx.msg != s->tx.cmp) freemsg(xchg(&s->tx.msg, NULL)); if (s->tx.cmp) freemsg(xchg(&s->tx.cmp, NULL)); if (s->rx.msg) freemsg(xchg(&s->rx.msg, NULL)); if (s->rx.nxt) freemsg(xchg(&s->rx.nxt, NULL)); if (s->rx.cmp) freemsg(xchg(&s->rx.cmp, NULL)); if ((*(s->prev) = s->next)) s->next->prev = s->prev; s->next = NULL; s->prev = &s->next; sdt_put(s); s->oq->q_ptr = NULL; flushq(s->oq, FLUSHALL); s->oq = NULL; sdt_put(s); s->iq->q_ptr = NULL; flushq(s->iq, FLUSHALL); s->iq = NULL; sdt_put(s); } lis_spin_unlock_irqrestore(&s->lock, &flags); sdt_put(s); /* final put */ } STATIC struct sdt *sdt_get(struct sdt *s) { atomic_inc(&s->refcnt); return (s); } STATIC void sdt_put(struct sdt *s) { if (atomic_dec_and_test(&s->refcnt)) { kmem_cache_free(sdt_priv_cachep, s); printd(("%s: %p: freed sdt private structure\n", SDT_MOD_NAME, s)); } } /* * ======================================================================= * * LiS Module Initialization (For unregistered driver.) * * ======================================================================= */ STATIC int sdt_initialized = 0; STATIC void sdt_init(void) { unless(sdt_initialized > 0, return); cmn_err(CE_NOTE, SDT_BANNER); /* console splash */ if ((sdt_initialized = sdt_init_caches()) || (sdt_initialized = sdt_init_tables())) { cmn_err(CE_PANIC, "%s: ERROR: could not allocate caches", SDT_MOD_NAME); } else if ((sdt_initialized = lis_register_strmod(&sdt_info, SDT_MOD_NAME)) < 0) { cmn_err(CE_WARN, "%s: couldn't register module", SDT_MOD_NAME); sdt_free_tables(); sdt_free_caches(); } return; } STATIC void sdt_terminate(void) { ensure(sdt_initialized > 0, return); if ((sdt_initialized = lis_unregister_strmod(&sdt_info)) < 0) { cmn_err(CE_PANIC, "%s: couldn't unregister module", SDT_MOD_NAME); } else { sdt_free_tables(); sdt_free_caches(); } return; } /* * ======================================================================= * * Kernel Module Initialization * * ======================================================================= */ int init_module(void) { sdt_init(); if (sdt_initialized < 0) return sdt_initialized; return (0); } void cleanup_module(void) { sdt_terminate(); }
|
|||||||||||||||||||||||||||
OpenSS7 SS7 for the Common Man |
Home | Overview | Status | News | Documentation | Resources | About | ||||||||||||||||||||
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |