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/ss7sctp/sdl_sctp.c#ident "@(#) $RCSfile: sdl_sctp.c,v $ $Name: $($Revision: 0.8.2.9 $) $Date: 2003/04/14 12:13:30 $" static char const ident[] = "$RCSfile: sdl_sctp.c,v $ $Name: $($Revision: 0.8.2.9 $) $Date: 2003/04/14 12:13:30 $"; #include <linux/config.h> #include <linux/version.h> #ifdef MODVERSIONS #include <linux/modversions.h> #endif #include <linux/module.h> #include <sys/stream.h> #include <sys/stropts.h> #include <sys/cmn_err.h> #include <sys/dki.h> #include <sys/npi.h> #include <sys/npi_sctp.h> #include <ss7/lmi.h> #include <ss7/lmi_ioctl.h> #include <ss7/devi.h> #include <ss7/devi_ioctl.h> #include <ss7/sdli.h> #include <ss7/sdli_ioctl.h> #include "../lock.h" #include "../debug.h" #include "../bufq.h" #define SDL_DESCRIP "SS7/SCTP SIGNALLING DATA LINK (SDL) STREAMS MODULE." #define SDL_COPYRIGHT "Copyright (c) 1997-2002 OpenSS7 Corporation. All Rights Reserved." #define SDL_DEVICE "Part of the OpenSS7 Stack for LiS STREAMS." #define SDL_CONTACT "Brian Bidulock <bidulock@openss7.org>" #define SDL_LICENSE "GPL" #define SDL_BANNER SDL_DESCRIP "\n" \ SDL_COPYRIGHT "\n" \ SDL_DEVICE "\n" \ SDL_CONTACT "\n" MODULE_AUTHOR(SDL_CONTACT); MODULE_DESCRIPTION(SDL_DESCRIP); MODULE_SUPPORTED_DEVICE(SDL_DEVICE); #ifdef MODULE_LICENSE MODULE_LICENSE(SDL_LICENSE); #endif //#define SDL_RX_COMPRESSION //#define SDL_TX_COMPRESSION typedef void (*bufcall_fnc_t) (long); /* * ========================================================================= * * STREAMS Definitions * * ========================================================================= */ static struct module_info sdl_minfo = { mi_idnum:0, /* Module ID number */ mi_idname:"sdl-sctp", /* Module name */ mi_minpsz:0, /* Min packet size accepted *//* FIXME */ mi_maxpsz:INFPSZ, /* Max packet size accepted *//* FIXME */ mi_hiwat:1 << 15, /* Hi water mark *//* FIXME */ mi_lowat:1 << 10, /* Lo water mark *//* FIXME */ }; static int sdl_open(queue_t *, dev_t *, int, int, cred_t *); static int sdl_close(queue_t *, int, cred_t *); static int sdl_rput(queue_t *, mblk_t *); static int sdl_rsrv(queue_t *); static struct qinit sdl_rinit = { qi_putp:sdl_rput, /* Read put (msg from below) */ qi_srvp:sdl_rsrv, /* Read queue service */ qi_qopen:sdl_open, /* Each open */ qi_qclose:sdl_close, /* Last close */ qi_minfo:&sdl_minfo, /* Information */ }; static int sdl_wput(queue_t *, mblk_t *); static int sdl_wsrv(queue_t *); static struct qinit sdl_winit = { qi_putp:sdl_wput, /* Write put (msg from above) */ qi_srvp:sdl_wsrv, /* Write queue service */ qi_minfo:&sdl_minfo, /* Information */ }; static struct streamtab sdl_info = { st_rdinit:&sdl_rinit, /* Upper read queue */ st_wrinit:&sdl_winit, /* Upper write queue */ }; /* * ========================================================================= * * SDL Private Structure * * ========================================================================= */ typedef struct sdl { struct sdl *next; queue_t *rq; queue_t *wq; lis_spin_lock_t lock; queue_t *rwait; queue_t *wwait; uint state; /* SDL interface state */ uint version; /* version executing */ uint flags; /* interface flags */ ulong token; /* my bind token */ mblk_t *rx_buf; /* RX compression buffer */ size_t rx_count; /* RX compression count */ mblk_t *tx_buf; /* TX compression buffer */ size_t tx_count; /* TX compression count */ uint timer_tick; /* tick timer */ lmi_option_t lmi_conf; /* protocol and variant options */ sdl_config_t sdl_conf; /* SDL configuration options */ dev_device_t dev_conf; /* DEV configuration options */ } sdl_t; #define SDL_PRIV(__q) ((sdl_t *)(__q)->q_ptr) /* * ========================================================================= * * Locking * * ========================================================================= */ static inline int sdl_trylockq(queue_t * q) { int res; sdl_t *s = SDL_PRIV(q); if (!(res = lis_spin_trylock(&s->lock))) { if (q == s->rq) s->rwait = q; if (q == s->wq) s->wwait = q; } return (res); } static inline int sdl_unlockq(queue_t * q) { sdl_t *s = SDL_PRIV(q); lis_spin_unlock(&s->lock); if (s->rwait) qenable(xchg(&s->rwait, NULL)); if (s->wwait) qenable(xchg(&s->wwait, NULL)); } #define SDL_LSSU_SIO 0 #define SDL_LSSU_SIN 1 #define SDL_LSSU_SIE 2 #define SDL_LSSU_SIOS 3 #define SDL_LSSU_SIPO 4 #define SDL_LSSU_SIB 5 #define SDL_LSS2_SIO 0 + 8 #define SDL_LSS2_SIN 1 + 8 #define SDL_LSS2_SIE 2 + 8 #define SDL_LSS2_SIOS 3 + 8 #define SDL_LSS2_SIPO 4 + 8 #define SDL_LSS2_SIB 5 + 8 #define SDL_FISU 16 #define SDL_MSU 17 #define SDL_FLAG_RX_ENABLED 0x01 #define SDL_FLAG_TX_ENABLED 0x02 #define SDL_EVENT_TX_WAKEUP 1 /* * ========================================================================= * * SDL Provider (SDL) -> SDL User Primitives * * ========================================================================= */ /* * LMI_INFO_ACK * --------------------------------------------- */ static int lmi_info_ack(sdl_t * sp) { mblk_t *mp; lmi_info_ack_t *p; ensure(sp, return (-EFAULT)); if ((mp = allocb(sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((lmi_info_ack_t *) mp->b_wptr)++; p->lmi_primitive = LMI_INFO_ACK; p->lmi_version = 1; p->lmi_state = sp->state; p->lmi_max_sdu = -1; p->lmi_min_sdu = 0; p->lmi_header_len = 0; p->lmi_ppa_style = LMI_STYLE1; putnext(sp->rq, mp); return (0); } rare(); return (-ENOBUFS); } #if 0 /* * LMI_OK_ACK * --------------------------------------------- */ static int lmi_ok_ack(sdl_t * sp, long prim) { mblk_t *mp; lmi_ok_ack_t *p; ensure(sp, return (-EFAULT)); if ((mp = allocb(sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((lmi_ok_ack_t *) mp->b_wptr)++; p->lmi_primitive = LMI_OK_ACK; p->lmi_correct_primitive = prim; switch (sp->state) { case LMI_ATTACH_PENDING: sp->state = LMI_DISABLED; break; case LMI_DETACH_PENDING: sp->state = LMI_UNATTACHED; break; /* default is don't change state */ } p->lmi_state = sp->state; putnext(sp->rq, mp); return (0); } rare(); return (-ENOBUFS); } #endif /* * LMI_ERROR_ACK * --------------------------------------------- */ static int lmi_error_ack(sdl_t * sp, long prim, long err) { mblk_t *mp; lmi_error_ack_t *p; switch (err) { case -EBUSY: case -EAGAIN: case -ENOMEM: case -ENOBUFS: seldom(); return (err); } ensure(sp, return (-EFAULT)); if ((mp = allocb(sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((lmi_error_ack_t *) mp->b_wptr)++; p->lmi_primitive = LMI_ERROR_ACK; p->lmi_errno = err < 0 ? -err : 0; p->lmi_reason = err < 0 ? LMI_SYSERR : err; p->lmi_error_primitive = prim; switch (sp->state) { case LMI_ATTACH_PENDING: sp->state = LMI_UNATTACHED; break; case LMI_DETACH_PENDING: sp->state = LMI_DISABLED; break; case LMI_ENABLE_PENDING: sp->state = LMI_DISABLED; break; case LMI_DISABLE_PENDING: sp->state = LMI_ENABLED; break; /* * Default is not to change state. */ } p->lmi_state = sp->state; putnext(sp->rq, mp); return (0); } rare(); return (-ENOBUFS); } /* * LMI_ENABLE_CON * --------------------------------------------- */ static int lmi_enable_con(sdl_t * sp) { mblk_t *mp; lmi_enable_con_t *p; ensure(sp, return (-EFAULT)); ensure(sp->state == LMI_ENABLE_PENDING, return (-EFAULT)); if (canputnext(sp->rq)) { if ((mp = allocb(sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((lmi_enable_con_t *) mp->b_wptr)++; p->lmi_primitive = LMI_ENABLE_CON; p->lmi_state = sp->state = LMI_ENABLED; putnext(sp->rq, mp); return (0); } rare(); return (-ENOBUFS); } rare(); return (-EBUSY); } /* * LMI_DISABLE_CON * --------------------------------------------- */ static int lmi_disable_con(sdl_t * sp) { mblk_t *mp; lmi_disable_con_t *p; ensure(sp, return (-EFAULT)); ensure(sp->state == LMI_DISABLE_PENDING, return (-EFAULT)); if (canputnext(sp->rq)) { if ((mp = allocb(sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((lmi_disable_con_t *) mp->b_wptr)++; p->lmi_primitive = LMI_DISABLE_CON; p->lmi_state = sp->state = LMI_DISABLED; putnext(sp->rq, mp); return (0); } rare(); return (-ENOBUFS); } rare(); return (-EBUSY); } #if 0 /* * LMI_OPTMGMT_ACK * --------------------------------------------- */ static int lmi_optmgmt_ack(sdl_t * sp, ulong flags, void *opt_ptr, size_t opt_len) { mblk_t *mp; lmi_optmgmt_ack_t *p; ensure(sp, return (-EFAULT)); if ((mp = allocb(sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((lmi_optmgmt_ack_t *) 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_mgmt_flags = flags; bcopy(opt_ptr, mp->b_wptr, opt_len); mp->b_wptr += opt_len; putnext(sp->rq, mp); return (0); } rare(); return (-ENOBUFS); } #endif /* * LMI_ERROR_IND * --------------------------------------------- */ #if 0 static int lmi_error_ind(sdl_t * sp, long err) { mblk_t *mp; lmi_error_ind_t *p; ensure(sp, return (-EFAULT)); if ((mp = allocb(sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((lmi_error_ind_t *) mp->b_wptr)++; p->lmi_primitive = LMI_ERROR_IND; p->lmi_errno = err < 0 ? -err : 0; p->lmi_reason = err < 0 ? LMI_SYSERR : err; p->lmi_state = sp->state; putnext(sp->rq, mp); return (0); } rare(); return (-ENOBUFS); } #endif /* * LMI_STATS_IND * --------------------------------------------- */ #if 0 static int lmi_stats_ind(sdl_t * sp, ulong interval, ulong timestamp) { mblk_t *mp; lmi_stats_ind_t *p; ensure(sp, return (-EFAULT)); if (canputnext(sp->rq)) { if ((mp = allocb(sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((lmi_stats_ind_t *) mp->b_wptr)++; p->lmi_primitive = LMI_STATS_IND; p->lmi_interval = interval; p->lmi_timestamp = timestamp; putnext(sp->rq, mp); return (0); } rare(); return (-ENOBUFS); } seldom(); return (-EBUSY); } #endif /* * LMI_EVENT_IND * --------------------------------------------- */ #if 0 static int lmi_event_ind(sdl_t * sp, ulong oid, ulong severity, ulong timestamp) { mblk_t *mp; lmi_event_ind_t *p; ensure(sp, return (-EFAULT)); if (canputnext(sp->rq)) { if ((mp = allocb(sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((lmi_event_ind_t *) mp->b_wptr)++; p->lmi_primitive = LMI_EVENT_IND; p->lmi_objectid = oid; p->lmi_timestamp = timestamp; p->lmi_severity = severity; putnext(sp->rq, mp); return (0); } rare(); return (-ENOBUFS); } seldom(); return (-EBUSY); } #endif /* * SDL_DAEDR_RECEIVED_BITS_IND * --------------------------------------------- */ static int sdl_read(sdl_t * sp, mblk_t * dp) { ensure(sp, return (-EFAULT)); if (canputnext(sp->rq)) { putnext(sp->rq, dp); return (0); } seldom(); return (-EBUSY); } #if 0 static int sdl_daedr_received_bits_ind(sdl_t * sp, ulong count, mblk_t * dp) { mblk_t *mp; sdl_daedr_received_bits_ind_t *p; ensure(sp, return (-EFAULT)); if (canputnext(sp->rq)) { if ((mp = allocb(sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((sdl_daedr_received_bits_ind_t *) mp->b_wptr)++; p->sdl_primitive = SDL_DAEDR_RECEIVED_BITS_IND; p->sdl_count = count; putnext(sp->rq, mp); return (0); } rare(); return (-ENOBUFS); } seldom(); return (-EBUSY); } #endif /* * SDL_DAEDR_CORRECT_SU_IND * --------------------------------------------- */ #if 0 static int sdl_daedr_correct_su_ind(sdl_t * sp, ulong count) { mblk_t *mp; sdl_daedr_correct_su_ind_t *p; ensure(sp, return (-EFAULT)); if ((mp = allocb(sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((sdl_daedr_correct_su_ind_t *) mp->b_wptr)++; p->sdl_primitive = SDL_DAEDR_CORRECT_SU_IND; p->sdl_count = count; putnext(sp->rq, mp); return (0); } rare(); return (-ENOBUFS); } #endif /* * SDL_DAEDR_SU_IN_ERROR_IND * --------------------------------------------- */ #if 0 static int sdl_daedr_su_in_error_ind(sdl_t * sp) { mblk_t *mp; sdl_daedr_su_in_error_ind_t *p; ensure(sp, return (-EFAULT)); if ((mp = allocb(sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((sdl_daedr_su_in_error_ind_t *) mp->b_wptr)++; p->sdl_primitive = SDL_DAEDR_SU_IN_ERROR_IND; putnext(sp->rq, mp); return (0); } rare(); return (-ENOBUFS); } #endif /* * SDL_DAEDT_TRANSMISSION_REQUEST_IND * --------------------------------------------- */ static int sdl_daedt_transmission_request_ind(sdl_t * sp) { mblk_t *mp; sdl_daedt_transmission_request_ind_t *p; ensure(sp, return (-EFAULT)); if ((mp = allocb(sizeof(*p), BPRI_MED))) { mp->b_datap->db_type = M_PCPROTO; p = ((sdl_daedt_transmission_request_ind_t *) mp->b_wptr)++; p->sdl_primitive = SDL_DAEDT_TRANSMISSION_REQUEST_IND; putnext(sp->rq, mp); return (0); } rare(); return (-ENOBUFS); } /* * ========================================================================= * * NPI User (SDL) -> NPI Provider (SCTP) Primitives * * ========================================================================= */ /* * N_DATA_REQ * --------------------------------------------- */ static int n_data_req(sdl_t * sp, ulong flags, void *qos_ptr, size_t qos_len, mblk_t * dp) { mblk_t *mp; N_data_req_t *p; ensure(sp, return (-EFAULT)); ensure(dp, return (-EFAULT)); if (canputnext(sp->wq)) { if ((mp = allocb(sizeof(*p) + qos_len, BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((N_data_req_t *) mp->b_wptr)++; p->PRIM_type = N_DATA_REQ; p->DATA_xfer_flags = flags; bcopy(qos_ptr, mp->b_wptr, qos_len); mp->b_wptr += qos_len; mp->b_cont = dp; putnext(sp->wq, mp); return (0); } rare(); return (-ENOBUFS); } seldom(); return (-EBUSY); } /* * N_EXDATA_REQ * --------------------------------------------- */ #if 0 static int n_exdata_req(sdl_t * sp, void *qos_ptr, size_t qos_len, mblk_t * dp) { mblk_t *mp; N_exdata_req_t *p; ensure(sp, return (-EFAULT)); ensure(dp, return (-EFAULT)); if (bcanputnext(sp->wq, 1)) { if ((mp = allocb(sizeof(*p) + qos_len, BPRI_MED))) { mp->b_datap->db_type = M_PROTO; p = ((N_exdata_req_t *) mp->b_wptr)++; p->PRIM_type = N_EXDATA_REQ; bcopy(qos_ptr, mp->b_wptr, qos_len); mp->b_wptr += qos_len; mp->b_cont = dp; putnext(sp->wq, mp); return (0); } rare(); return (-ENOBUFS); } seldom(); return (-EBUSY); } #endif /* * ========================================================================= * * SDL PDU Message Functions * * ========================================================================= */ #define SDL_PPI 10 static int sdl_write(sdl_t * sp, mblk_t * mp) { int err; uint xsn = sp->lmi_conf.popt & SS7_POPT_XSN; size_t mlen = mp->b_wptr - mp->b_rptr; N_qos_sel_data_sctp_t qos = { N_QOS_SEL_DATA_SCTP, SDL_PPI, 0, 0, 0, 0 }; if ((err = n_data_req(sp, 0, &qos, sizeof(qos), mp))) return (err); if ((!xsn && mlen > 5) || (xsn && mlen > 8)) sdl_daedt_transmission_request_ind(sp); return (0); } /* * ========================================================================= * * SDL Provider (SDL) <- SDL User Primitives * * ========================================================================= */ /* * LMI_INFO_REQ * --------------------------------------------- */ static int lmi_info_req(sdl_t * sp, mblk_t * mp) { (void) mp; ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); return lmi_info_ack(sp); } /* * LMI_ATTACH_REQ * --------------------------------------------- */ static int lmi_attach_req(sdl_t * sp, mblk_t * mp) { int err; size_t mlen = mp->b_wptr - mp->b_rptr; lmi_attach_req_t *p = (lmi_attach_req_t *) mp->b_rptr; ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); do { if (mlen >= sizeof(*p)) { if (sp->state == LMI_UNATTACHED) { sp->state = LMI_ATTACH_PENDING; lmi_error_ack(sp, LMI_ATTACH_REQ, LMI_NOTSUPP); } seldom(); err = LMI_OUTSTATE; break; /* would place interface out of state */ } seldom(); err = LMI_PROTOSHORT; break; /* M_PROTO block too short */ } while (0); seldom(); return lmi_error_ack(sp, LMI_ATTACH_REQ, err); } /* * LMI_DETACH_REQ * --------------------------------------------- */ static int lmi_detach_req(sdl_t * sp, mblk_t * mp) { int err; size_t mlen = mp->b_wptr - mp->b_rptr; lmi_detach_req_t *p = (lmi_detach_req_t *) mp->b_rptr; ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); do { if (mlen >= sizeof(*p)) { if (sp->state == LMI_DISABLED) { sp->state = LMI_DETACH_PENDING; lmi_error_ack(sp, LMI_DETACH_REQ, LMI_NOTSUPP); } seldom(); err = LMI_OUTSTATE; break; /* would place interface out of state */ } seldom(); err = LMI_PROTOSHORT; break; /* M_PROTO block too short */ } while (0); seldom(); return lmi_error_ack(sp, LMI_DETACH_REQ, err); } /* * LMI_ENABLE_REQ * --------------------------------------------- */ static int lmi_enable_req(sdl_t * sp, mblk_t * mp) { int err; size_t mlen = mp->b_wptr - mp->b_rptr; lmi_enable_req_t *p = (lmi_enable_req_t *) mp->b_rptr; ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); do { if (mlen >= sizeof(*p)) { if (sp->state == LMI_DISABLED) { sp->state = LMI_ENABLE_PENDING; return lmi_enable_con(sp); } seldom(); err = LMI_OUTSTATE; break; /* would place interface out of state */ } seldom(); err = LMI_PROTOSHORT; break; /* M_PROTO block too short */ } while (0); seldom(); return lmi_error_ack(sp, LMI_ENABLE_REQ, err); } /* * LMI_DISABLE_REQ * --------------------------------------------- */ static int lmi_disable_req(sdl_t * sp, mblk_t * mp) { int err; size_t mlen = mp->b_wptr - mp->b_rptr; lmi_disable_req_t *p = (lmi_disable_req_t *) mp->b_rptr; ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); do { if (mlen >= sizeof(*p)) { if (sp->state == LMI_ENABLED || sp->state == LMI_ENABLE_PENDING) { sp->state = LMI_DISABLE_PENDING; freemsg(xchg(&sp->rx_buf, NULL)); sp->rx_count = 0; freemsg(xchg(&sp->tx_buf, NULL)); sp->tx_count = 0; return lmi_disable_con(sp); } seldom(); err = LMI_OUTSTATE; break; /* would place interface out of state */ } seldom(); err = LMI_PROTOSHORT; break; /* M_PROTO block too short */ } while (0); seldom(); return lmi_error_ack(sp, LMI_DISABLE_REQ, err); } /* * LMI_OPTMGMT_REQ * --------------------------------------------- */ static int lmi_optmgmt_req(sdl_t * sp, mblk_t * mp) { int err; size_t mlen = mp->b_wptr - mp->b_rptr; lmi_optmgmt_req_t *p = (lmi_optmgmt_req_t *) mp->b_rptr; ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); do { if (mlen >= sizeof(*p)) { lmi_error_ack(sp, LMI_OPTMGMT_REQ, LMI_NOTSUPP); } seldom(); err = LMI_PROTOSHORT; break; /* M_PROTO block too short */ } while (0); seldom(); return lmi_error_ack(sp, LMI_OPTMGMT_REQ, err); } /* * SDL_DAEDT_TRAMSMISSION_REQ * --------------------------------------------- */ #ifndef abs #define abs(x) ((x)<0?-(x):(x)) #endif static int m_error_reply(sdl_t * sp, int err) { mblk_t *mp; ensure(sp, return (-EFAULT)); switch (err) { case -EBUSY: case -EAGAIN: case -ENOMEM: case -ENOBUFS: seldom(); return (err); case 0: case 1: case 2: never(); return (err); } if ((mp = allocb(2, BPRI_HI))) { mp->b_datap->db_type = M_ERROR; *(mp->b_wptr)++ = abs(err); *(mp->b_wptr)++ = abs(err); putnext(sp->rq, mp); return (0); } rare(); return (-ENOBUFS); } static int sdl_daedt_xmit_req(sdl_t * sp, mblk_t * mp) { int err; mblk_t *dp; size_t mlen = mp->b_wptr - mp->b_rptr; sdl_daedt_transmission_req_t *p = (sdl_daedt_transmission_req_t *) mp->b_rptr; ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); do { if ((dp = mp->b_cont)) { if (mlen >= sizeof(*p)) { if (sp->state != LMI_DISABLED) { if (sp->state == LMI_ENABLED) { if (sp->flags & SDL_FLAG_TX_ENABLED) { if ((err = sdl_write(sp, dp))) break; mp->b_cont = NULL; /* absorbed data portion */ return (0); } rare(); return (0); /* ignore if not enabled */ } seldom(); err = LMI_OUTSTATE; break; /* would place interface out of state */ } seldom(); return (0); break; /* ingore data in DISABLED state */ } seldom(); err = LMI_PROTOSHORT; break; /* M_PROTO block too short */ } rare(); err = -EFAULT; break; /* no M_DATA blocks */ } while (0); rare(); return m_error_reply(sp, err); /* XXX */ } /* * SDL_DAEDT_START_REQ * --------------------------------------------- */ static int sdl_daedt_start_req(sdl_t * sp, mblk_t * mp) { int err; size_t mlen = mp->b_wptr - mp->b_rptr; sdl_daedt_start_req_t *p = (sdl_daedt_start_req_t *) mp->b_rptr; ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); do { if (mlen >= sizeof(*p)) { if (sp->state == LMI_ENABLED) { /* enable the transmitter section */ sp->flags |= SDL_FLAG_TX_ENABLED; return (0); } seldom(); err = LMI_OUTSTATE; break; /* would place interface out of state */ } seldom(); err = LMI_PROTOSHORT; break; /* M_PROTO block too short */ } while (0); rare(); return m_error_reply(sp, err); /* XXX */ } /* * SDL_DAEDR_START_REQ * --------------------------------------------- */ static int sdl_daedr_start_req(sdl_t * sp, mblk_t * mp) { int err; size_t mlen = mp->b_wptr - mp->b_rptr; sdl_daedr_start_req_t *p = (sdl_daedr_start_req_t *) mp->b_rptr; ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); do { if (mlen >= sizeof(*p)) { if (sp->state == LMI_ENABLED) { /* enable the receiver section */ sp->flags |= SDL_FLAG_RX_ENABLED; return (0); } seldom(); err = LMI_OUTSTATE; break; /* would place interface out of state */ } seldom(); err = LMI_PROTOSHORT; break; /* M_PROTO block too short */ } while (0); rare(); return m_error_reply(sp, err); /* XXX */ } /* * ========================================================================= * * NPI User (SDL) <- NPI Provider (SCTP) Primitives * * ========================================================================= */ /* * N_CONN_IND * --------------------------------------------- */ static int n_conn_ind(sdl_t * sp, mblk_t * mp) { ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); (void) sp; (void) mp; rare(); return (0); } /* * N_CONN_CON * --------------------------------------------- */ static int n_conn_con(sdl_t * sp, mblk_t * mp) { ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); (void) sp; (void) mp; rare(); return (0); } /* * N_DISCON_IND * --------------------------------------------- */ static int n_discon_ind(sdl_t * sp, mblk_t * mp) { ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); (void) sp; (void) mp; rare(); return (0); } /* * N_DATA_IND * --------------------------------------------- */ static int n_data_ind(sdl_t * sp, mblk_t * mp) { int err; mblk_t *dp; size_t mlen = mp->b_wptr - mp->b_rptr; N_data_ind_t *p = (N_data_ind_t *) mp->b_rptr; ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); ensure(mlen >= sizeof(*p), return (-EFAULT)); if (mlen <= sp->sdl_conf.m) { if ((dp = mp->b_cont)) { if (sp->state == LMI_ENABLED) { if (sp->flags & SDL_FLAG_RX_ENABLED) { if (canputnext(sp->rq)) { if ((err = sdl_read(sp, dp))) return (err); mp->b_cont = NULL; /* absorbed data portion */ return (0); } seldom(); return (-EBUSY); /* flow controlled */ } seldom(); return (0); /* ignore unless enabled */ } rare(); return (-EPROTO); /* ignore data in other states */ } rare(); return (-EFAULT); } rare(); return (-EMSGSIZE); } /* * N_EXDATA_IND * --------------------------------------------- */ static int n_exdata_ind(sdl_t * sp, mblk_t * mp) { int err; mblk_t *dp; size_t mlen = mp->b_wptr - mp->b_rptr; N_exdata_ind_t *p = (N_exdata_ind_t *) mp->b_rptr; ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); ensure(mlen >= sizeof(*p), return (-EFAULT)); if (mlen <= sp->sdl_conf.m) { if ((dp = mp->b_cont)) { if (sp->state == LMI_ENABLED) { if (sp->flags & SDL_FLAG_RX_ENABLED) { if (bcanputnext(sp->rq, 1)) { if ((err = sdl_read(sp, dp))) return (err); mp->b_cont = NULL; /* absorbed data portion */ return (0); } seldom(); return (-EBUSY); /* flow controlled */ } seldom(); return (0); /* ignore unless enabled */ } rare(); return (-EPROTO); /* ignore data in other states */ } rare(); return (-EFAULT); } rare(); return (-EMSGSIZE); } /* * N_DATACK_IND * --------------------------------------------- */ static int n_datack_ind(sdl_t * sp, mblk_t * mp) { ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); (void) sp; (void) mp; rare(); return (0); } /* * N_INFO_ACK * --------------------------------------------- */ static int n_info_ack(sdl_t * sp, mblk_t * mp) { ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); (void) sp; (void) mp; rare(); return (0); } /* * N_BIND_ACK * --------------------------------------------- */ static int n_bind_ack(sdl_t * sp, mblk_t * mp) { ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); (void) sp; (void) mp; rare(); return (0); } /* * N_OK_ACK * --------------------------------------------- */ static int n_ok_ack(sdl_t * sp, mblk_t * mp) { ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); (void) sp; (void) mp; rare(); return (0); } /* * N_ERROR_ACK * --------------------------------------------- */ static int n_error_ack(sdl_t * sp, mblk_t * mp) { ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); (void) sp; (void) mp; rare(); return (0); } /* * N_RESET_IND * --------------------------------------------- */ static int n_reset_ind(sdl_t * sp, mblk_t * mp) { ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); (void) sp; (void) mp; rare(); return (0); } /* * N_RESET_CON * --------------------------------------------- */ static int n_reset_con(sdl_t * sp, mblk_t * mp) { ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); (void) sp; (void) mp; rare(); return (0); } /* * ========================================================================= * * IO Controls * * ========================================================================= * I have only implemented enough of these to get the Q.781 test programs * running. */ /* * SDL_IOCGOPTIONS * --------------------------------------------- */ static int sdl_iocgoptions(queue_t * q, int cmd, void *arg) { sdl_t *sp; lmi_option_t *opt = (lmi_option_t *) arg; ensure(q, return (-EFAULT)); sp = (sdl_t *) q->q_ptr; ensure(sp, return (-EFAULT)); ensure(arg, return (-EFAULT)); *opt = sp->lmi_conf; return (0); } /* * SDL_IOCSOPTIONS * --------------------------------------------- */ static int sdl_iocsoptions(queue_t * q, int cmd, void *arg) { sdl_t *sp; lmi_option_t *opt = (lmi_option_t *) arg; ensure(q, return (-EFAULT)); sp = (sdl_t *) q->q_ptr; ensure(sp, return (-EFAULT)); ensure(arg, return (-EFAULT)); switch (opt->pvar) { case SS7_PVAR_ITUT_88: case SS7_PVAR_ITUT_93: case SS7_PVAR_ITUT_96: case SS7_PVAR_ITUT_00: case SS7_PVAR_ANSI_88: case SS7_PVAR_ANSI_92: case SS7_PVAR_ANSI_96: case SS7_PVAR_ANSI_00: case SS7_PVAR_ETSI_88: case SS7_PVAR_ETSI_93: case SS7_PVAR_ETSI_96: case SS7_PVAR_ETSI_00: case SS7_PVAR_JTTC_94: break; default: rare(); return (-EINVAL); } if (opt->popt & ~(SS7_POPT_MPLEV | SS7_POPT_HSL | SS7_POPT_XSN)) { rare(); return (-EINVAL); } sp->lmi_conf = *opt; return (0); } /* * SDL_IOCGCONFIG * --------------------------------------------- */ static int sdl_iocgconfig(queue_t * q, int cmd, void *arg) { sdl_t *sp; sdl_config_t *cnf = (sdl_config_t *) arg; ensure(q, return (-EFAULT)); sp = (sdl_t *) q->q_ptr; ensure(sp, return (-EFAULT)); ensure(arg, return (-EFAULT)); *cnf = sp->sdl_conf; return (0); } /* * SDL_IOCSCONFIG * --------------------------------------------- */ static int sdl_iocsconfig(queue_t * q, int cmd, void *arg) { sdl_t *sp; sdl_config_t *cnf = (sdl_config_t *) arg; ensure(q, return (-EFAULT)); sp = (sdl_t *) q->q_ptr; ensure(sp, return (-EFAULT)); ensure(arg, return (-EFAULT)); sp->sdl_conf = *cnf; return (0); } /* * DEV_IOCSIFCLOCK * --------------------------------------------- */ static int dev_iocsifclock(queue_t * q, int cmd, void *arg) { sdl_t *sp; ulong *val = (ulong *) arg; ensure(q, return (-EFAULT)); sp = (sdl_t *) q->q_ptr; ensure(sp, return (-EFAULT)); ensure(arg, return (-EFAULT)); switch (*val) { case DEV_CLOCK_NONE: case DEV_CLOCK_ABR: case DEV_CLOCK_SHAPER: case DEV_CLOCK_TICK: sp->dev_conf.ifclock = *val; return (0); default: case DEV_CLOCK_INT: case DEV_CLOCK_EXT: case DEV_CLOCK_LOOP: case DEV_CLOCK_MASTER: case DEV_CLOCK_SLAVE: case DEV_CLOCK_DPLL: break; } return (-EINVAL); } /* * DEV_IOCGIFCLOCK * --------------------------------------------- */ static int dev_iocgifclock(queue_t * q, int cmd, void *arg) { sdl_t *sp; ulong *val = (ulong *) arg; ensure(q, return (-EFAULT)); sp = (sdl_t *) q->q_ptr; ensure(sp, return (-EFAULT)); ensure(arg, return (-EFAULT)); *val = sp->dev_conf.ifclock; return (0); } /* * DEV_IOCCDISCTX * --------------------------------------------- * Disconnect the transmit path. */ static int dev_ioccdisctx(queue_t * q, int cmd, void *arg) { ensure(q, return (-EFAULT)); ensure(arg, return (-EFAULT)); return (-EOPNOTSUPP); } /* * DEV_IOCCCONNTX * --------------------------------------------- * Reconnect the transmit path. */ static int dev_ioccconntx(queue_t * q, int cmd, void *arg) { ensure(q, return (-EFAULT)); ensure(arg, return (-EFAULT)); return (-EOPNOTSUPP); } /* * ========================================================================= * * STREAMS Message Handling * * ========================================================================= * ------------------------------------------------------------------------- * * M_PROTO, M_PCPROTO Handling * * ------------------------------------------------------------------------- */ static int sdl_w_proto(queue_t * q, mblk_t * mp) { int rtn; ulong prim; sdl_t *sp; ulong oldstate; ensure(q, return (-EFAULT)); sp = (sdl_t *) q->q_ptr; oldstate = sp->state; ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); switch ((prim = *((ulong *) mp->b_rptr))) { case LMI_INFO_REQ: rtn = lmi_info_req(sp, mp); break; case LMI_ATTACH_REQ: rtn = lmi_attach_req(sp, mp); break; case LMI_DETACH_REQ: rtn = lmi_detach_req(sp, mp); break; case LMI_ENABLE_REQ: rtn = lmi_enable_req(sp, mp); break; case LMI_DISABLE_REQ: rtn = lmi_disable_req(sp, mp); break; case LMI_OPTMGMT_REQ: rtn = lmi_optmgmt_req(sp, mp); break; case SDL_DAEDT_TRANSMISSION_REQ: rtn = sdl_daedt_xmit_req(sp, mp); break; case SDL_DAEDT_START_REQ: rtn = sdl_daedt_start_req(sp, mp); break; case SDL_DAEDR_START_REQ: rtn = sdl_daedr_start_req(sp, mp); break; default: rtn = -EOPNOTSUPP; break; } if (rtn < 0) { seldom(); sp->state = oldstate; } return (rtn); } static int sdl_r_proto(queue_t * q, mblk_t * mp) { int rtn; ulong prim; sdl_t *sp; ensure(q, return (-EFAULT)); sp = (sdl_t *) q->q_ptr; ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); switch ((prim = *((ulong *) mp->b_rptr))) { case N_CONN_IND: rtn = n_conn_ind(sp, mp); break; case N_CONN_RES: rtn = n_conn_con(sp, mp); break; case N_DISCON_IND: rtn = n_discon_ind(sp, mp); break; case N_DATA_IND: rtn = n_data_ind(sp, mp); break; case N_EXDATA_IND: rtn = n_exdata_ind(sp, mp); break; case N_DATACK_IND: rtn = n_datack_ind(sp, mp); break; case N_INFO_ACK: rtn = n_info_ack(sp, mp); break; case N_BIND_ACK: rtn = n_bind_ack(sp, mp); break; case N_OK_ACK: rtn = n_ok_ack(sp, mp); break; case N_ERROR_ACK: rtn = n_error_ack(sp, mp); break; case N_RESET_IND: rtn = n_reset_ind(sp, mp); break; case N_RESET_CON: rtn = n_reset_con(sp, mp); break; default: rtn = -EOPNOTSUPP; break; } if (rtn < 0) { seldom(); } return (rtn); } /* * ------------------------------------------------------------------------- * * M_DATA Handling * * ------------------------------------------------------------------------- */ static int sdl_w_data(queue_t * q, mblk_t * mp) { int err; sdl_t *sp; ensure(q, return (-EFAULT)); sp = (sdl_t *) q->q_ptr; ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); if ((err = sdl_write(sp, mp))) return err; return (1); /* absorbed mblk */ } static int sdl_r_data(queue_t * q, mblk_t * mp) { int err; sdl_t *sp; ensure(q, return (-EFAULT)); sp = (sdl_t *) q->q_ptr; ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); if ((err = sdl_read(sp, mp))) return err; return (1); /* absorbed mblk */ } /* * ------------------------------------------------------------------------- * * M_CTL Handling (Events) * * ------------------------------------------------------------------------- */ #if 0 static int sdl_r_ctl(queue_t * q, mblk_t * mp) { sdl_t *sp; ensure(q, return (-EFAULT)); sp = (sdl_t *) q->q_ptr; ensure(sp, return (-EFAULT)); ensure(mp, return (-EFAULT)); switch (*mp->b_rptr) { case SDL_EVENT_TX_WAKEUP: sdl_tx_wakeup(sp); return (0); } return (-EOPNOTSUPP); } #endif /* * ------------------------------------------------------------------------- * * M_IOCTL Handling * * ------------------------------------------------------------------------- */ static int sdl_w_ioctl(queue_t * q, mblk_t * mp) { 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; struct linkblk *lp = (struct linkblk *) arg; int ret = -EINVAL; int type = _IOC_TYPE(cmd); int nr = _IOC_NR(cmd); int size = _IOC_SIZE(cmd); (void) nr; ensure(q, return (-EFAULT)); ensure(mp, return (-EFAULT)); switch (type) { case __SID: switch (cmd) { default: ptrace(("Unknown IOCTL %x\n", cmd)); case I_STR: case I_LINK: case I_PLINK: case I_UNLINK: case I_PUNLINK: rare(); (void) lp; ret = -EINVAL; break; } ret = -EOPNOTSUPP; break; case SDL_IOC_MAGIC: if (count >= size) { switch (cmd) { case SDL_IOCGOPTIONS: ret = sdl_iocgoptions(q, cmd, arg); break; case SDL_IOCSOPTIONS: ret = sdl_iocsoptions(q, cmd, arg); break; case SDL_IOCGCONFIG: ret = sdl_iocgconfig(q, cmd, arg); break; case SDL_IOCSCONFIG: ret = sdl_iocsconfig(q, cmd, arg); break; default: case SDL_IOCTCONFIG: case SDL_IOCCCONFIG: case SDL_IOCGSTATEM: case SDL_IOCCMRESET: case SDL_IOCGSTATSP: case SDL_IOCSSTATSP: case SDL_IOCGSTATS: case SDL_IOCCSTATS: case SDL_IOCGNOTIFY: case SDL_IOCSNOTIFY: case SDL_IOCCNOTIFY: ret = -EOPNOTSUPP; break; } } else ret = -EINVAL; break; case DEV_IOC_MAGIC: if (count >= size) { switch (cmd) { case DEV_IOCSIFCLOCK: ret = dev_iocsifclock(q, cmd, arg); break; case DEV_IOCGIFCLOCK: ret = dev_iocgifclock(q, cmd, arg); break; case DEV_IOCCDISCTX: ret = dev_ioccdisctx(q, cmd, arg); break; case DEV_IOCCCONNTX: ret = dev_ioccconntx(q, cmd, arg); break; default: case DEV_IOCCIFRESET: case DEV_IOCGIFFLAGS: case DEV_IOCSIFFLAGS: case DEV_IOCGIFTYPE: case DEV_IOCSIFTYPE: case DEV_IOCGGRPTYPE: case DEV_IOCSGRPTYPE: case DEV_IOCGIFMODE: case DEV_IOCSIFMODE: case DEV_IOCGIFRATE: case DEV_IOCSIFRATE: case DEV_IOCGIFCODING: case DEV_IOCSIFCODING: case DEV_IOCGIFLEADS: case DEV_IOCSIFLEADS: case DEV_IOCCIFLEADS: ret = -EOPNOTSUPP; break; } } else ret = -EINVAL; break; default: if (q->q_next) { putnext(q, mp); return (1); } ret = -EOPNOTSUPP; break; } if (ret >= 0) { mp->b_datap->db_type = M_IOCACK; iocp->ioc_error = 0; iocp->ioc_rval = 0; } else { seldom(); mp->b_datap->db_type = M_IOCNAK; iocp->ioc_error = -ret; iocp->ioc_rval = -1; } qreply(q, mp); return (1); } /* * ------------------------------------------------------------------------- * * M_ERROR Handling * * ------------------------------------------------------------------------- */ static int sdl_r_error(queue_t * q, mblk_t * mp) { ensure(q, return (-EFAULT)); ensure(mp, return (-EFAULT)); putnext(q, mp); return (1); } /* * ------------------------------------------------------------------------- * * M_FLUSH Handling * * ------------------------------------------------------------------------- */ static int sdl_m_flush(queue_t * q, mblk_t * mp, const uint8_t mflag) { ensure(q, return (-EFAULT)); ensure(mp, return (-EFAULT)); if (*mp->b_rptr & mflag) { if (*mp->b_rptr & FLUSHBAND) flushband(q, mp->b_rptr[1], FLUSHALL); else flushq(q, FLUSHALL); } putnext(q, mp); return (1); } static int sdl_w_flush(queue_t * q, mblk_t * mp) { ensure(q, return (-EFAULT)); ensure(mp, return (-EFAULT)); return sdl_m_flush(q, mp, FLUSHW); } static int sdl_r_flush(queue_t * q, mblk_t * mp) { ensure(q, return (-EFAULT)); ensure(mp, return (-EFAULT)); return sdl_m_flush(q, mp, FLUSHR); } /* * ------------------------------------------------------------------------- * * Other messages (e.g. M_IOCACK) * * ------------------------------------------------------------------------- */ static int sdl_m_other(queue_t * q, mblk_t * mp) { rare(); ensure(q, return (-EFAULT)); ensure(mp, return (-EFAULT)); if (mp->b_datap->db_type >= QPCTL || bcanputnext(q, mp->b_band)) { putnext(q, mp); return (1); } else return (-EBUSY); } /* * ========================================================================= * * PUT and SRV * * ========================================================================= */ /* * SDL Write Put and Service */ static int sdl_wput(queue_t * q, mblk_t * mp) { int rtn; ensure(q, return (-EFAULT)); ensure(mp, return (-EFAULT)); if (mp->b_datap->db_type < QPCTL && q->q_count) { seldom(); putq(q, mp); return (0); } if (sdl_trylockq(q)) { switch (mp->b_datap->db_type) { case M_DATA: rtn = sdl_w_data(q, mp); break; case M_PROTO: case M_PCPROTO: rtn = sdl_w_proto(q, mp); break; case M_FLUSH: rtn = sdl_w_flush(q, mp); break; case M_IOCTL: rtn = sdl_w_ioctl(q, mp); break; default: rtn = sdl_m_other(q, mp); break; } switch (rtn) { case 0: assert(mp->b_datap->db_ref); freemsg(mp); case 1: break; case 2: assert(mp->b_datap->db_ref); freeb(mp); break; case -ENOBUFS: /* should set up bufcall */ case -EBUSY: case -EAGAIN: case -ENOMEM: seldom(); putq(q, mp); sdl_unlockq(q); return (0); default: rare(); ptrace(("Error = %d\n", rtn)); assert(mp->b_datap->db_ref); freemsg(mp); sdl_unlockq(q); return (rtn); } } else { rare(); putq(q, mp); } return (0); } static int sdl_wsrv(queue_t * q) { int rtn; mblk_t *mp; ensure(q, return (-EFAULT)); if (sdl_trylockq(q)) { while ((mp = getq(q))) { switch (mp->b_datap->db_type) { case M_DATA: rtn = sdl_w_data(q, mp); break; case M_PROTO: case M_PCPROTO: rtn = sdl_w_proto(q, mp); break; case M_FLUSH: rtn = sdl_w_flush(q, mp); break; case M_IOCTL: rtn = sdl_w_ioctl(q, mp); break; default: rtn = sdl_m_other(q, mp); break; } switch (rtn) { case 0: assert(mp->b_datap->db_ref); freemsg(mp); case 1: continue; case 2: assert(mp->b_datap->db_ref); freeb(mp); continue; case -ENOBUFS: /* should set up bufcall */ case -EBUSY: case -EAGAIN: case -ENOMEM: seldom(); if (mp->b_datap->db_type < QPCTL) { putbq(q, mp); sdl_unlockq(q); return (0); } __ptrace(("This should never happen!\n")); if (mp->b_datap->db_type == M_PCPROTO) { mp->b_datap->db_type = M_PROTO; putq(q, mp); sdl_unlockq(q); return (0); } default: rare(); ptrace(("Error = %d\n", rtn)); assert(mp->b_datap->db_ref); freemsg(mp); continue; } } } else { rare(); qenable(q); } return (0); } /* * SCTP Read Put and Service */ static int sdl_rput(queue_t * q, mblk_t * mp) { int rtn; ensure(q, return (-EFAULT)); ensure(mp, return (-EFAULT)); if (mp->b_datap->db_type < QPCTL && q->q_count) { seldom(); putq(q, mp); return (0); } if (sdl_trylockq(q)) { switch (mp->b_datap->db_type) { case M_DATA: rtn = sdl_r_data(q, mp); break; case M_PROTO: case M_PCPROTO: rtn = sdl_r_proto(q, mp); break; // case M_CTL: rtn = sdl_r_ctl (q, mp); break; case M_ERROR: rtn = sdl_r_error(q, mp); break; case M_FLUSH: rtn = sdl_r_flush(q, mp); break; default: rtn = sdl_m_other(q, mp); break; } switch (rtn) { case 0: assert(mp->b_datap->db_ref); freemsg(mp); case 1: break; case 2: assert(mp->b_datap->db_ref); freeb(mp); break; case -ENOBUFS: /* should set up bufcall */ case -EBUSY: case -EAGAIN: case -ENOMEM: seldom(); putq(q, mp); sdl_unlockq(q); return (0); default: rare(); ptrace(("Error = %d\n", rtn)); assert(mp->b_datap->db_ref); freemsg(mp); sdl_unlockq(q); return (rtn); } } else { rare(); putq(q, mp); } return (0); } static int sdl_rsrv(queue_t * q) { int rtn; mblk_t *mp; ensure(q, return (-EFAULT)); if (sdl_trylockq(q)) { while ((mp = getq(q))) { switch (mp->b_datap->db_type) { case M_DATA: rtn = sdl_r_data(q, mp); break; case M_PROTO: case M_PCPROTO: rtn = sdl_r_proto(q, mp); break; // case M_CTL: rtn = sdl_r_ctl (q, mp); break; case M_ERROR: rtn = sdl_r_error(q, mp); break; case M_FLUSH: rtn = sdl_r_flush(q, mp); break; default: rtn = sdl_m_other(q, mp); break; } switch (rtn) { case 0: assert(mp->b_datap->db_ref); freemsg(mp); case 1: continue; case 2: assert(mp->b_datap->db_ref); freeb(mp); continue; case -ENOBUFS: /* should set up bufcall */ case -EBUSY: case -EAGAIN: case -ENOMEM: seldom(); if (mp->b_datap->db_type < QPCTL) { putbq(q, mp); sdl_unlockq(q); return (0); } __ptrace(("This should never happen!\n")); if (mp->b_datap->db_type == M_PCPROTO) { mp->b_datap->db_type = M_PROTO; putq(q, mp); sdl_unlockq(q); return (0); } default: rare(); ptrace(("Error = %d\n", rtn)); assert(mp->b_datap->db_ref); freemsg(mp); continue; } } } else { rare(); qenable(q); } return (0); } /* * ========================================================================= * * Private Structure allocation, deallocation and cache * * ========================================================================= */ kmem_cache_t *sdl_cachep = NULL; static void sdl_init_caches(void) { if (!sdl_cachep && !(sdl_cachep = kmem_cache_create ("sdl_cachep", sizeof(sdl_t), 0, SLAB_HWCACHE_ALIGN, NULL, NULL))) panic("%s:Cannot alloc sdl_cachep.\n", __FUNCTION__); return; } static void sdl_term_caches(void) { if (sdl_cachep) if (kmem_cache_destroy(sdl_cachep)) cmn_err(CE_WARN, "%s: did not destroy sdl_cachep", __FUNCTION__); return; } static sdl_t *sdl_alloc_priv(queue_t * q) { sdl_t *sp; ensure(q, return (NULL)); if ((sp = kmem_cache_alloc(sdl_cachep, SLAB_ATOMIC))) { bzero(sp, sizeof(*sp)); RD(q)->q_ptr = WR(q)->q_ptr = sp; sp->rq = RD(q); sp->wq = WR(q); sp->state = LMI_DISABLED; lis_spin_lock_init(&sp->lock, "ss7sctp-private"); } return (sp); } static void sdl_free_priv(queue_t * q) { sdl_t *sp; ensure(q, return); sp = (sdl_t *) q->q_ptr; ensure(sp, return); untimeout(xchg(&sp->timer_tick, 0)); freemsg(xchg(&sp->rx_buf, NULL)); freemsg(xchg(&sp->tx_buf, NULL)); kmem_cache_free(sdl_cachep, sp); return; } /* * ========================================================================= * * OPEN and CLOSE * * ========================================================================= */ static int sdl_open(queue_t * q, dev_t * devp, int flag, int sflag, cred_t * crp) { (void) crp; /* for now */ if (q->q_ptr != NULL) /* already open */ return (0); if (sflag == MODOPEN || WR(q)->q_next != NULL) { // fixme(("Check module we are being pushed over.\n")); if (!(sdl_alloc_priv(q))) return ENOMEM; return (0); } return EIO; } static int sdl_close(queue_t * q, int flag, cred_t * crp) { (void) flag; (void) crp; sdl_free_priv(q); return (0); } /* * ========================================================================= * * Lis Module Initialization * * ========================================================================= */ void sdl_init(void) { int modnum; unless(sdl_minfo.mi_idnum, return); cmn_err(CE_NOTE, SDL_BANNER); /* console splash */ sdl_init_caches(); if (!(modnum = lis_register_strmod(&sdl_info, sdl_minfo.mi_idname))) { sdl_minfo.mi_idnum = 0; rare(); cmn_err(CE_NOTE, "sdl: couldn't register as module\n"); return; } sdl_minfo.mi_idnum = modnum; return; } void sdl_terminate(void) { ensure(sdl_minfo.mi_idnum, return); if ((sdl_minfo.mi_idnum = lis_unregister_strmod(&sdl_info))) cmn_err(CE_WARN, "sdl: couldn't unregister as module!\n"); sdl_term_caches(); return; } /* * ========================================================================= * * Kernel Module Initialization * * ========================================================================= */ int init_module(void) { sdl_init(); return (0); } void cleanup_module(void) { sdl_terminate(); return; }
|
|||||||||||||||||||||||||||
OpenSS7 SS7 for the Common Man |
Home | Overview | Status | News | Documentation | Resources | About | ||||||||||||||||||||
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |