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/mtp/mtp_npi.c#ident "@(#) $RCSfile: mtp_npi.c,v $ $Name: $($Revision: 0.8.2.2 $) $Date: 2003/06/16 09:03:57 $" static char const ident[] = "$RCSfile: mtp_npi.c,v $ $Name: $($Revision: 0.8.2.2 $) $Date: 2003/06/16 09:03:57 $"; /* * This is a MTP NPI module which can be pushed over an MTPI (Message * Transfer Part Interface) stream to effect an NPI interface to the MTP. * This module is intended to be used by application programs or by upper * modules that expect an NPI connectionless service provider. */ #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 <ss7/lmi.h> #include <ss7/lmi_ioctl.h> #include <ss7/mtpi.h> #include <ss7/mtpi_ioctl.h> #include <sys/npi.h> #include <sys/npi_ss7.h> #include <sys/npi_mtp.h> #include "../debug.h" #include "../bufq.h" #include "../priv.h" #include "../lock.h" #include "../queue.h" #include "../allocb.h" #include "../timer.h" #undef INLINE #define INLINE /* let compiler do its job */ #define MTP_DESCRIP "SS7 Message Transfer Part (MTP) NPI STREAMS MODULE." #define MTP_COPYRIGHT "Copyright (c) 1997-2003 OpenSS7 Corporation. All Rights Reserved." #define MTP_DEVICE "Part of the OpenSS7 Stack for LiS STREAMS." #define MTP_CONTACT "Brian Bidulock <bidulock@openss7.org>" #define MTP_LICENSE "GPL" #define MTP_BANNER MTP_DESCRIP "\n" \ MTP_COPYRIGHT "\n" \ MTP_DEVICE "\n" \ MTP_CONTACT MODULE_AUTHOR(MTP_CONTACT); MODULE_DESCRIPTION(MTP_DESCRIP); MODULE_SUPPORTED_DEVICE(MTP_DEVICE); #ifdef MODULE_LICENSE MODULE_LICENSE(MTP_LICENSE); #endif /* * ========================================================================= * * STREAMS Definitions * * ========================================================================= */ #define MTP_MOD_ID MTP_IOC_MAGIC #define MTP_MOD_NAME "mtp-npi" STATIC struct module_info mtp_minfo = { mi_idnum:MTP_MOD_ID, /* Module ID number */ mi_idname:MTP_MOD_NAME, /* Module name */ mi_minpsz:1, /* Min packet size accepted */ mi_maxpsz:INFPSZ, /* Max packet size accepted */ mi_hiwat:1 << 15, /* Hi water mark */ mi_lowat:1 << 10, /* Lo water mark */ }; STATIC int mtp_open(queue_t *, dev_t *, int, int, cred_t *); STATIC int mtp_close(queue_t *, int, cred_t *); STATIC struct qinit mtp_rinit = { qi_putp:ss7_oput, /* Read put (msg from below) */ qi_qopen:mtp_open, /* Each open */ qi_qclose:mtp_close, /* Last close */ qi_minfo:&mtp_minfo, /* Information */ }; STATIC struct qinit mtp_winit = { qi_putp:ss7_iput, /* Write put (msg from above) */ qi_minfo:&mtp_minfo, /* Information */ }; STATIC struct streamtab mtp_info = { st_rdinit:&mtp_rinit, /* Upper read queue */ st_wrinit:&mtp_winit, /* Upper write queue */ }; /* * ========================================================================= * * MTP-NPI Private Structure * * ========================================================================= */ typedef struct mtp { STR_DECLARATION (struct mtp); /* stream declaration */ struct mtp_addr src; struct mtp_addr dst; struct { ulong pvar; ulong popt; ulong sls; ulong mp; ulong debug; ulong sls_mask; } options; N_info_ack_t prot; } mtp_t; #define MTP_PRIV(__q) ((struct mtp *)(__q)->q_ptr) struct mtp *mtp_opens = NULL; STATIC struct mtp *mtp_alloc_priv(queue_t *q, struct mtp **, dev_t *, cred_t *); STATIC struct mtp *mtp_get(struct mtp *); STATIC void mtp_put(struct mtp *); STATIC void mtp_free_priv(queue_t *q); /* * ------------------------------------------------------------------------- * * QOS Parameters * * ------------------------------------------------------------------------- */ typedef struct mtp_opts { uint flags; /* success flags */ ulong *sls; ulong *mp; ulong *debug; } mtp_opts_t; struct { ulong sls; ulong mp; ulong debug; } opt_defaults = { 0, 0, 0}; STATIC int mtp_parse_qos(struct mtp *mtp, struct mtp_opts *ops, unsigned char *op, size_t len) { fixme(("Write this function\n")); return (-EFAULT); } /* * ------------------------------------------------------------------------- * * STATE Functions * * ------------------------------------------------------------------------- */ #ifdef _DEBUG STATIC INLINE const char *mtp_state(ulong state) { switch (state) { case NS_UNBND: return ("NS_UNBND"); case NS_WACK_BREQ: return ("NS_WACK_BREQ"); case NS_WACK_UREQ: return ("NS_WACK_UREQ"); case NS_IDLE: return ("NS_IDLE"); case NS_WACK_OPTREQ: return ("NS_WACK_OPTREQ"); case NS_WACK_RRES: return ("NS_WACK_RRES"); case NS_WCON_CREQ: return ("NS_WCON_CREQ"); case NS_WRES_CIND: return ("NS_WRES_CIND"); case NS_WACK_CRES: return ("NS_WACK_CRES"); case NS_DATA_XFER: return ("NS_DATA_XFER"); case NS_WCON_RREQ: return ("NS_WCON_RREQ"); case NS_WRES_RIND: return ("NS_WRES_RIND"); case NS_WACK_DREQ6: return ("NS_WACK_DREQ6"); case NS_WACK_DREQ7: return ("NS_WACK_DREQ7"); case NS_WACK_DREQ9: return ("NS_WACK_DREQ9"); case NS_WACK_DREQ10: return ("NS_WACK_DREQ10"); case NS_WACK_DREQ11: return ("NS_WACK_DREQ11"); case NS_NOSTATES: return ("NS_NOSTATES"); default: return ("????"); } } #endif STATIC INLINE ulong mtp_get_state(struct mtp * mtp) { return mtp->i_state; } STATIC INLINE void mtp_set_state(struct mtp *mtp, ulong newstate) { ulong oldstate = mtp->i_state; (void) oldstate; printd(("%s: %p: %s <- %s\n", MTP_MOD_NAME, mtp, mtp_state(newstate), mtp_state(oldstate))); mtp->i_state = mtp->prot.CURRENT_state = newstate; } STATIC INLINE int mtp_bind(struct mtp *mtp, struct mtp_addr *src) { if (src) mtp->src = *src; return (0); } STATIC INLINE int mtp_connect(struct mtp *mtp, struct mtp_addr *dst) { return (0); } STATIC INLINE int mtp_unbind(struct mtp *mtp) { return (0); } STATIC INLINE int mtp_disconnect(struct mtp *mtp) { return (0); } /* * ========================================================================= * * PRIMITIVES * * ========================================================================= */ /* * Primitives sent upstream * ------------------------------------------------------------------------- */ /* * M_ERROR * ----------------------------------- */ STATIC INLINE int m_error(queue_t *q, struct mtp *mtp, int etype) { int err; mblk_t *mp; if (!(mp = ss7_allocb(q, 2, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_ERROR; *(mp->b_wptr)++ = etype < 0 ? -etype : etype; *(mp->b_wptr)++ = etype < 0 ? -etype : etype; mtp_set_state(mtp, NS_NOSTATES); printd(("%s: %p: <- M_ERROR\n", MTP_MOD_NAME, mtp)); putnext(mtp->oq, mp); return (QR_DONE); enobufs: err = -ENOBUFS; rare(); goto error; error: return (err); } STATIC INLINE int n_error_ack(queue_t *q, struct mtp *mtp, ulong prim, long error); /* * N_CONN_IND 11 - Incoming connection indication * ----------------------------------------------------------- */ STATIC INLINE int n_conn_ind(queue_t *q, struct mtp *mtp, ulong seq, ulong flags, struct mtp_addr *src, struct mtp_addr *dst, N_qos_sel_conn_mtp_t *qos) { int err; mblk_t *mp; N_conn_ind_t *p; const size_t src_len = src ? sizeof(*src) : 0; const size_t dst_len = dst ? sizeof(*dst) : 0; const size_t qos_len = qos ? sizeof(*qos) : 0; const size_t msg_len = sizeof(*p) + src_len + dst_len + qos_len; if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->PRIM_type = N_CONN_IND; p->SRC_length = src_len; p->SRC_offset = src_len ? sizeof(*p) : 0; p->DEST_length = dst_len; p->DEST_offset = dst_len ? sizeof(*p) + src_len : 0; p->QOS_length = qos_len; p->QOS_offset = qos_len ? sizeof(*p) + src_len + dst_len : 0; p->SEQ_number = seq; p->CONN_flags = flags; if (src_len) { bcopy(mp->b_wptr, src, src_len); mp->b_wptr += src_len; } if (dst_len) { bcopy(mp->b_wptr, dst, dst_len); mp->b_wptr += dst_len; } if (qos_len) { bcopy(mp->b_wptr, qos, qos_len); mp->b_wptr += qos_len; } printd(("%s: %p: <- N_CONN_IND\n", MTP_MOD_NAME, mtp)); putnext(mtp->oq, mp); return (QR_DONE); enobufs: err = -ENOBUFS; ptrace(("%s: %d: ERROR: no buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * N_CONN_CON 12 - Connection established * ----------------------------------------------------------- */ STATIC INLINE int n_conn_con(queue_t *q, struct mtp *mtp, ulong flags, struct mtp_addr *res, N_qos_sel_conn_mtp_t *qos) { int err; mblk_t *mp; N_conn_con_t *p; const size_t res_len = res ? sizeof(*res) : 0; const size_t qos_len = qos ? sizeof(*qos) : 0; const size_t msg_len = sizeof(*p) + res_len; if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->PRIM_type = N_CONN_CON; p->RES_length = res_len; p->RES_offset = res_len ? sizeof(*p) : 0; p->CONN_flags = flags; p->QOS_length = qos_len; p->QOS_offset = qos_len ? sizeof(*p) + res_len : 0; if (res_len) { bcopy(mp->b_wptr, res, res_len); mp->b_wptr += res_len; } if (qos_len) { bcopy(mp->b_wptr, qos, qos_len); mp->b_wptr += qos_len; } if (mtp_get_state(mtp) != NS_WCON_CREQ) swerr(); mtp_set_state(mtp, NS_DATA_XFER); printd(("%s: %p: <- N_CONN_CON\n", MTP_MOD_NAME, mtp)); putnext(mtp->oq, mp); return (QR_DONE); enobufs: err = -ENOBUFS; ptrace(("%s: %d: ERROR: no buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * N_DISCON_IND 13 - NC disconnected * ----------------------------------------------------------- */ STATIC INLINE int n_discon_ind(queue_t *q, struct mtp *mtp, ulong orig, ulong reason, ulong seq, struct mtp_addr *res, mblk_t *dp) { int err; mblk_t *mp; N_discon_ind_t *p; const size_t res_len = res ? sizeof(*res) : 0; const size_t msg_len = sizeof(*p) + res_len; if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->PRIM_type = N_DISCON_IND; p->DISCON_orig = orig; p->DISCON_reason = reason; p->RES_length = res_len; p->RES_offset = res_len ? sizeof(*p) : 0; p->SEQ_number = seq; if (res_len) { bcopy(mp->b_wptr, res, res_len); mp->b_wptr += res_len; } mp->b_cont = dp; printd(("%s: %p: <- N_DISCON_IND\n", MTP_MOD_NAME, mtp)); putnext(mtp->oq, mp); return (QR_DONE); enobufs: err = -ENOBUFS; ptrace(("%s: %d: ERROR: no buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * N_DATA_IND 14 - Incoming connection-mode data indication * ----------------------------------------------------------- */ STATIC INLINE int n_data_ind(queue_t *q, struct mtp *mtp, ulong flags, mblk_t *dp) { int err; mblk_t *mp; N_data_ind_t *p; const size_t msg_len = sizeof(*p); if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->PRIM_type = N_DATA_IND; p->DATA_xfer_flags = flags; mp->b_cont = dp; printd(("%s: %p: <- N_DATA_IND\n", MTP_MOD_NAME, mtp)); putnext(mtp->oq, mp); return (QR_ABSORBED); enobufs: err = -ENOBUFS; ptrace(("%s: %d: ERROR: no buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * N_EXDATA_IND 15 - Incoming expedited data indication * ----------------------------------------------------------- */ STATIC INLINE int n_exdata_ind(queue_t *q, struct mtp *mtp, mblk_t *dp) { int err; mblk_t *mp; N_exdata_ind_t *p; if (!(mp = ss7_allocb(q, sizeof(*p), BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PROTO; mp->b_band = 1; p = ((typeof(p)) mp->b_wptr)++; p->PRIM_type = N_EXDATA_IND; mp->b_cont = dp; printd(("%s: %p: <- N_EXDATA_IND\n", MTP_MOD_NAME, mtp)); putnext(mtp->oq, mp); return (QR_ABSORBED); enobufs: err = -ENOBUFS; ptrace(("%s: %d: ERROR: no buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * N_INFO_ACK 16 - Information Acknowledgement * ----------------------------------------------------------- */ STATIC INLINE int n_info_ack(queue_t *q, struct mtp *mtp) { int err; mblk_t *mp; N_info_ack_t *p; size_t src_len, dst_len, msg_len; N_qos_sel_info_mtp_t *qos; N_qos_range_info_mtp_t *qor; size_t qos_len = sizeof(*qos); size_t qor_len = sizeof(*qor); switch (mtp_get_state(mtp)) { default: case NS_UNBND: src_len = 0; dst_len = 0; break; case NS_IDLE: src_len = sizeof(mtp->src); dst_len = 0; break; case NS_DATA_XFER: src_len = sizeof(mtp->src); dst_len = sizeof(mtp->dst); break; } msg_len = sizeof(*p) + src_len + dst_len + qos_len + qor_len; if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; *p = mtp->prot; p->ADDR_size = sizeof(struct mtp_addr); p->ADDR_length = src_len + dst_len; p->ADDR_offset = src_len + dst_len ? sizeof(*p) : 0; p->QOS_length = qos_len; p->QOS_offset = qos_len ? sizeof(*p) + src_len + dst_len : 0; p->QOS_range_length = qor_len; p->QOS_range_offset = qor_len ? sizeof(*p) + src_len + dst_len + qos_len : 0; p->PROTOID_length = 0; p->PROTOID_offset = 0; if (src_len) { bcopy(&mtp->src, mp->b_wptr, sizeof(mtp->src)); mp->b_wptr += sizeof(mtp->src); } if (dst_len) { bcopy(&mtp->dst, mp->b_wptr, sizeof(mtp->dst)); mp->b_wptr += sizeof(mtp->dst); } if (qos_len) { qos = ((typeof(qos)) mp->b_wptr)++; qos->n_qos_type = N_QOS_SEL_INFO_MTP; qos->pvar = mtp->options.pvar; qos->popt = mtp->options.popt; } if (qor_len) { qor = ((typeof(qor)) mp->b_wptr)++; qor->n_qos_type = N_QOS_RANGE_INFO_MTP; qor->sls_range = mtp->options.sls_mask; qor->mp_range = (mtp->options.popt & SS7_POPT_MPLEV) ? 3 : 0; } printd(("%s: %p: <- N_INFO_ACK\n", MTP_MOD_NAME, mtp)); putnext(mtp->oq, mp); return (QR_DONE); enobufs: err = -ENOBUFS; ptrace(("%s: %d: ERROR: no buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * N_BIND_ACK 17 - NS User bound to network address * ----------------------------------------------------------- */ STATIC INLINE int n_bind_ack(queue_t *q, struct mtp *mtp, struct mtp_addr *add) { int err; mblk_t *mp; N_bind_ack_t *p; size_t add_len = add ? sizeof(*add) : 0; if (!(mp = ss7_allocb(q, sizeof(*p) + add_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->PRIM_type = N_BIND_ACK; p->ADDR_length = add_len; p->ADDR_offset = add_len ? sizeof(*p) : 0; p->CONIND_number = 0; p->TOKEN_value = (ulong) mtp->oq; p->PROTOID_length = 0; p->PROTOID_offset = 0; if (add_len) { bcopy(add, mp->b_wptr, add_len); mp->b_wptr += add_len; } if ((err = mtp_bind(mtp, add))) goto free_error; mtp_set_state(mtp, NS_IDLE); printd(("%s: %p: <- N_BIND_ACK\n", MTP_MOD_NAME, mtp)); putnext(mtp->oq, mp); return (QR_DONE); enobufs: err = -ENOBUFS; ptrace(("%s: %d: ERROR: no buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); free_error: freemsg(mp); return n_error_ack(q, mtp, N_BIND_REQ, err); } /* * N_ERROR_ACK 18 - Error Acknowledgement * ----------------------------------------------------------- */ STATIC INLINE int n_error_ack(queue_t *q, struct mtp *mtp, ulong prim, long etype) { int err = etype; mblk_t *mp; N_error_ack_t *p; size_t msg_len = sizeof(*p); switch (etype) { case -EBUSY: case -EAGAIN: case -ENOMEM: case -ENOBUFS: seldom(); goto error; case QR_DONE: case QR_ABSORBED: case QR_TRIMMED: swerr(); goto error; } if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->PRIM_type = N_ERROR_ACK; p->ERROR_prim = prim; p->NPI_error = etype < 0 ? NSYSERR : etype; p->UNIX_error = etype < 0 ? -etype : 0; printd(("%s: %p: <- N_ERROR_ACK\n", MTP_MOD_NAME, mtp)); putnext(mtp->oq, mp); /* Retruning -EPROTO here will make sure that the old state is restored correctly. If we return QR_DONE, then the state will never be restored. */ if (etype >= 0) return (-EPROTO); return (QR_DONE); enobufs: err = -ENOBUFS; ptrace(("%s: %d: ERROR: no buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * N_OK_ACK 19 - Success Acknowledgement * ----------------------------------------------------------- */ STATIC INLINE int n_ok_ack(queue_t *q, struct mtp *mtp, ulong prim) { int err; mblk_t *mp; N_ok_ack_t *p; size_t msg_len = sizeof(*p); if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PCPROTO; p = ((typeof(p)) mp->b_wptr)++; p->PRIM_type = N_OK_ACK; p->CORRECT_prim = prim; switch (mtp_get_state(mtp)) { case NS_WACK_UREQ: if ((err = mtp_unbind(mtp))) return (err); mtp_set_state(mtp, NS_UNBND); break; case NS_WACK_OPTREQ: mtp_set_state(mtp, NS_IDLE); break; case NS_WACK_RRES: mtp_set_state(mtp, NS_DATA_XFER); break; case NS_WACK_CRES: mtp_set_state(mtp, NS_DATA_XFER); break; case NS_WACK_DREQ6: case NS_WACK_DREQ7: case NS_WACK_DREQ9: case NS_WACK_DREQ10: case NS_WACK_DREQ11: if ((err = mtp_disconnect(mtp))) return (err); mtp_set_state(mtp, NS_IDLE); break; default: /* Note: if we are not in a WACK state we simply do not change state. This occurs normally when we are responding to a N_OPTMGMT_REQ in other than TS_IDLE state. */ seldom(); break; } printd(("%s: %p: <- N_OK_ACK\n", MTP_MOD_NAME, mtp)); putnext(mtp->oq, mp); return (QR_DONE); enobufs: err = -ENOBUFS; ptrace(("%s: %d: ERROR: no buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * N_UNITDATA_IND 20 - Connection-less data receive indication * ----------------------------------------------------------- */ STATIC INLINE int n_unitdata_ind(queue_t *q, struct mtp *mtp, struct mtp_addr *src, struct mtp_addr *dst, mblk_t *dp) { int err; mblk_t *mp; N_unitdata_ind_t *p; size_t src_len = src ? sizeof(*src) : 0; size_t dst_len = dst ? sizeof(*dst) : 0; size_t msg_len = sizeof(*p) + src_len + dst_len; if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->PRIM_type = N_UNITDATA_IND; p->SRC_length = src_len; p->SRC_offset = src_len ? sizeof(*p) : 0; p->DEST_length = dst_len; p->DEST_offset = dst_len ? sizeof(*p) + src_len : 0; if (src_len) { bcopy(src, mp->b_wptr, src_len); mp->b_wptr += src_len; } if (dst_len) { bcopy(dst, mp->b_wptr, dst_len); mp->b_wptr += dst_len; } mp->b_cont = dp; printd(("%s: %p: <- N_UNITDATA_IND\n", MTP_MOD_NAME, mtp)); putnext(mtp->oq, mp); return (QR_ABSORBED); enobufs: err = -ENOBUFS; ptrace(("%s: %d: ERROR: no buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * N_UDERROR_IND 21 - UNITDATA Error Indication * ----------------------------------------------------------- */ STATIC INLINE int n_uderror_ind(queue_t *q, struct mtp *mtp, struct mtp_addr *dst, mblk_t *dp, ulong etype) { int err; mblk_t *mp; N_uderror_ind_t *p; size_t dst_len = dst ? sizeof(*dst) : 0; size_t msg_len = sizeof(*p) + dst_len; if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->PRIM_type = N_UDERROR_IND; p->DEST_length = dst_len; p->DEST_offset = dst_len ? sizeof(*p) : 0; p->ERROR_type = etype; if (dst_len) { bcopy(dst, mp->b_wptr, dst_len); mp->b_wptr += dst_len; } mp->b_cont = dp; printd(("%s: %p: <- N_UDERROR_IND\n", MTP_MOD_NAME, mtp)); putnext(mtp->oq, mp); return (QR_DONE); enobufs: err = -ENOBUFS; ptrace(("%s: %d: ERROR: no buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * N_DATACK_IND 24 - Data acknowledgement indication * ----------------------------------------------------------- */ STATIC INLINE int n_datack_ind(queue_t *q, struct mtp *mtp) { int err; mblk_t *mp; N_datack_ind_t *p; size_t msg_len = sizeof(*p); if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->PRIM_type = N_DATACK_IND; printd(("%s: %p: <- N_DATACK_IND\n", MTP_MOD_NAME, mtp)); putnext(mtp->oq, mp); return (QR_DONE); enobufs: err = -ENOBUFS; ptrace(("%s: %d: ERROR: no buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * N_RESET_IND 26 - Incoming NC reset request indication * ----------------------------------------------------------- */ STATIC INLINE int n_reset_ind(queue_t *q, struct mtp *mtp, ulong orig, ulong reason) { int err; mblk_t *mp; N_reset_ind_t *p; size_t msg_len = sizeof(*p); if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->PRIM_type = N_RESET_IND; p->RESET_orig = orig; p->RESET_reason = reason; printd(("%s: %p: <- N_RESET_IND\n", MTP_MOD_NAME, mtp)); putnext(mtp->oq, mp); return (QR_DONE); enobufs: err = -ENOBUFS; ptrace(("%s: %d: ERROR: no buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * N_RESET_CON 28 - Reset processing complete * ----------------------------------------------------------- */ STATIC INLINE int n_reset_con(queue_t *q, struct mtp *mtp) { int err; mblk_t *mp; N_reset_con_t *p; size_t msg_len = sizeof(*p); if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PROTO; p = ((typeof(p)) mp->b_wptr)++; p->PRIM_type = N_RESET_CON; printd(("%s: %p: <- N_RESET_CON\n", MTP_MOD_NAME, mtp)); putnext(mtp->oq, mp); return (QR_DONE); enobufs: err = -ENOBUFS; ptrace(("%s: %d: ERROR: no buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * ------------------------------------------------------------------------- * * Primitives sent downstream. * * ------------------------------------------------------------------------- */ /* * MTP_BIND_REQ 1 - Bind to an MTP-SAP * ----------------------------------------------------------- */ STATIC INLINE int mtp_bind_req(queue_t *q, struct mtp *mtp, struct mtp_addr *add, ulong flags) { int err; mblk_t *mp; struct MTP_bind_req *p; size_t add_len = add ? sizeof(*add) : 0; size_t msg_len = sizeof(*p); if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PCPROTO; p = (typeof(p)) mp->b_wptr++; p->mtp_primitive = MTP_BIND_REQ; p->mtp_addr_length = add_len; p->mtp_addr_offset = add_len ? sizeof(*p) : 0; p->mtp_bind_flags = flags; if (add_len) { bcopy(add, mp->b_wptr, add_len); mp->b_wptr += add_len; } putnext(mtp->iq, mp); return (QR_DONE); enobufs: err = -ENOBUFS; ptrace(("%s: %p: ERROR: No buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * MTP_UNBIND_REQ 2 - Unbind from an MTP-SAP * ----------------------------------------------------------- */ STATIC INLINE int mtp_unbind_req(queue_t *q, struct mtp *mtp) { int err; mblk_t *mp; struct MTP_unbind_req *p; size_t msg_len = sizeof(*p); if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PCPROTO; p = (typeof(p)) mp->b_wptr++; p->mtp_primitive = MTP_UNBIND_REQ; putnext(mtp->iq, mp); return (QR_DONE); enobufs: err = -ENOBUFS; ptrace(("%s: %p: ERROR: No buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * MTP_CONN_REQ 3 - Connect to a remote MTP-SAP * ----------------------------------------------------------- */ STATIC INLINE int mtp_conn_req(queue_t *q, struct mtp *mtp, struct mtp_addr *add, ulong flags, mblk_t *dp) { int err; mblk_t *mp; struct MTP_conn_req *p; size_t add_len = add ? sizeof(*add) : 0; size_t msg_len = sizeof(*p) + add_len; if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PROTO; p = (typeof(p)) mp->b_wptr++; p->mtp_primitive = MTP_CONN_REQ; p->mtp_addr_length = add_len; p->mtp_addr_offset = add_len ? sizeof(*p) : 0; p->mtp_conn_flags = flags; if (add_len) { bcopy(add, mp->b_wptr, add_len); mp->b_wptr += add_len; } mp->b_cont = dp; putnext(mtp->iq, mp); return (QR_ABSORBED); enobufs: err = -ENOBUFS; ptrace(("%s: %p: ERROR: No buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * MTP_DISCON_REQ 4 - Disconnect from a remote MTP-SAP * ----------------------------------------------------------- */ STATIC INLINE int mtp_discon_req(queue_t *q, struct mtp *mtp) { int err; mblk_t *mp; struct MTP_discon_req *p; size_t msg_len = sizeof(*p); if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PROTO; p = (typeof(p)) mp->b_wptr++; p->mtp_primitive = MTP_DISCON_REQ; putnext(mtp->iq, mp); return (QR_DONE); enobufs: err = -ENOBUFS; ptrace(("%s: %p: ERROR: No buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * MTP_ADDR_REQ 5 - Address service * ----------------------------------------------------------- */ STATIC INLINE int mtp_addr_req(queue_t *q, struct mtp *mtp) { int err; mblk_t *mp; struct MTP_addr_req *p; size_t msg_len = sizeof(*p); if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PCPROTO; p = (typeof(p)) mp->b_wptr++; p->mtp_primitive = MTP_ADDR_REQ; putnext(mtp->iq, mp); return (QR_DONE); enobufs: err = -ENOBUFS; ptrace(("%s: %p: ERROR: No buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * MTP_INFO_REQ 6 - Information service * ----------------------------------------------------------- */ STATIC INLINE int mtp_info_req(queue_t *q, struct mtp *mtp) { int err; mblk_t *mp; struct MTP_info_req *p; size_t msg_len = sizeof(*p); if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PCPROTO; p = (typeof(p)) mp->b_wptr++; p->mtp_primitive = MTP_INFO_REQ; putnext(mtp->iq, mp); return (QR_DONE); enobufs: err = -ENOBUFS; ptrace(("%s: %p: ERROR: No buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } #if 0 /* * MTP_OPTMGMT_REQ 7 - Options management service * ----------------------------------------------------------- */ STATIC INLINE int mtp_optmgmt_req(queue_t *q, struct mtp *mtp, struct mtp_opts *opt, ulong flags) { int err; mblk_t *mp; struct MTP_optmgmt_req *p; size_t opt_len = opt ? mtp_opts_size(opt) : 0; size_t msg_len = sizeof(*p) + opt_len; if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PROTO; p = (typeof(p)) mp->b_wptr++; p->mtp_primitive = MTP_OPTMGMT_REQ; p->mtp_opt_length = opt_len; p->mtp_opt_offset = opt_len ? sizeof(*p) : 0; p->mtp_mgmt_flags = flags; if (opt_len) { mtp_build_opts(opt, mp->b_wptr); mp->b_wptr += opt_len; } putnext(mtp->iq, mp); return (QR_DONE); enobufs: err = -ENOBUFS; ptrace(("%s: %p: ERROR: No buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } #endif /* * MTP_TRANSFER_REQ 8 - MTP data transfer request * ----------------------------------------------------------- */ STATIC INLINE int mtp_transfer_req(queue_t *q, struct mtp *mtp, struct mtp_addr *dst, ulong pri, ulong sls, mblk_t *dp) { int err; mblk_t *mp; struct MTP_transfer_req *p; size_t dst_len = dst ? sizeof(*dst) : 0; size_t msg_len = sizeof(*p) + dst_len; if (!(mp = ss7_allocb(q, msg_len, BPRI_MED))) goto enobufs; mp->b_datap->db_type = M_PROTO; p = (typeof(p)) mp->b_wptr++; p->mtp_primitive = MTP_TRANSFER_REQ; p->mtp_dest_length = dst_len; p->mtp_dest_offset = dst_len ? sizeof(*p) : 0; p->mtp_mp = pri; p->mtp_sls = sls; if (dst_len) { bcopy(dst, mp->b_wptr, dst_len); mp->b_wptr += dst_len; } mp->b_cont = dp; putnext(mtp->iq, mp); return (QR_ABSORBED); enobufs: err = -ENOBUFS; ptrace(("%s: %p: ERROR: No buffers\n", MTP_MOD_NAME, mtp)); goto error; error: return (err); } /* * ------------------------------------------------------------------------- * * Primitives received from above. * * ------------------------------------------------------------------------- */ /* * M_DATA * ------------------------------------------------------------------- */ STATIC int n_data(queue_t *q, struct mtp *mtp, mblk_t *mp) { int err; const size_t dlen = msgdsize(mp); if (mtp->prot.SERV_type == N_CLNS) goto notsupport; if (dlen == 0 || dlen > mtp->prot.NSDU_size || dlen > mtp->prot.NIDU_size) goto baddata; switch (mtp_get_state(mtp)) { case NS_DATA_XFER: return mtp_transfer_req(q, mtp, &mtp->dst, mtp->options.mp, mtp->options.sls, mp); case NS_IDLE: goto ignore; default: goto outstate; } ignore: /* If we are in the idle state this is just spurious data, ignore it */ rare(); return (QR_DONE); outstate: err = NOUTSTATE; ptrace(("%s: %p: ERROR: would place i/f out of state\n", MTP_MOD_NAME, mtp)); goto error; notsupport: err = NNOTSUPPORT; ptrace(("%s: %p: ERROR: primitive not supported\n", MTP_MOD_NAME, mtp)); goto error; baddata: err = -EPROTO; ptrace(("%s: %p: ERROR: bad data\n", MTP_MOD_NAME, mtp)); goto error; error: return m_error(q, mtp, -EPROTO); } /* * N_CONN_REQ: * ------------------------------------------------------------------- */ STATIC int n_conn_req(queue_t *q, struct mtp *mtp, mblk_t *mp) { int err; const N_conn_req_t *p = (typeof(p)) mp->b_rptr; struct mtp_addr *dst; // unsigned char *qos; struct mtp_opts opts; if (mtp_get_state(mtp) != NS_IDLE) goto outstate; if (mtp->prot.SERV_type == N_CLNS) goto notsupport; if (mp->b_wptr < mp->b_rptr) goto badprim; if (mp->b_wptr < mp->b_rptr + p->DEST_offset + p->DEST_length) goto badprim; if (mp->b_wptr < mp->b_rptr + p->QOS_offset + p->QOS_length) goto badprim; dst = (typeof(dst)) (mp->b_rptr + p->DEST_offset); if (!p->DEST_length) goto noaddr; if (p->DEST_length < sizeof(*dst)) goto badaddr; if (dst->family != AF_MTP) goto badaddr; if (dst->si == 0 && mtp->src.si == 0) goto noaddr; if (dst->si < 3 && mtp->src.si != 0) goto badaddr; if (mtp_parse_qos(mtp, &opts, mp->b_rptr + p->QOS_offset, p->QOS_length)) goto badqostype; /* TODO: set options first */ mtp->dst = *dst; mtp_set_state(mtp, NS_WCON_CREQ); return n_conn_con(q, mtp, 0, &mtp->dst, NULL); badqostype: err = NBADQOSTYPE; ptrace(("%s: %p: ERROR: bad qos type\n", MTP_MOD_NAME, mtp)); goto error; #if 0 badqosparam: err = NBADQOSPARAM; ptrace(("%s: %p: ERROR: bad qos parameter\n", MTP_MOD_NAME, mtp)); goto error; #endif badaddr: err = NBADADDR; ptrace(("%s: %p: ERROR: bad destination address\n", MTP_MOD_NAME, mtp)); goto error; noaddr: err = NNOADDR; ptrace(("%s: %p: ERROR: couldn't allocate destination address\n", MTP_MOD_NAME, mtp)); goto error; badprim: err = -EMSGSIZE; ptrace(("%s: %p: ERROR: invalid primitive format\n", MTP_MOD_NAME, mtp)); goto error; notsupport: err = NNOTSUPPORT; ptrace(("%s: %p: ERROR: primitive not supported for N_CLNS\n", MTP_MOD_NAME, mtp)); goto error; outstate: err = NOUTSTATE; ptrace(("%s: %p: ERROR: would place i/f out of state\n", MTP_MOD_NAME, mtp)); goto error; error: return n_error_ack(q, mtp, N_CONN_REQ, err); } /* * N_CONN_RES: * ------------------------------------------------------------------- */ STATIC int n_conn_res(queue_t *q, struct mtp *mtp, mblk_t *mp) { int err; const N_conn_res_t *p = (typeof(p)) mp->b_rptr; if (mtp->prot.SERV_type == N_CLNS) goto notsupport; if (mtp_get_state(mtp) != NS_WRES_CIND) goto outstate; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto badprim; /* We never give an N_CONN_IND, so there is no reason for a N_CONN_RES. We probably could do this * (issue an N_CONN_IND on a listening stream when there is no other MTP user for the SI value and * send a UPU on an N_DISCON_REQ or just redirect all traffic for that user on a N_CONN_RES) but * that is for later. */ goto eopnotsupp; eopnotsupp: err = -EOPNOTSUPP; ptrace(("%s: %p: ERROR: operation not supported\n", MTP_MOD_NAME, mtp)); goto error; badprim: err = -EMSGSIZE; ptrace(("%s: %p: ERROR: invalid primitive format\n", MTP_MOD_NAME, mtp)); goto error; outstate: err = NOUTSTATE; ptrace(("%s: %p: ERROR: would place i/f out of state\n", MTP_MOD_NAME, mtp)); goto error; notsupport: err = NNOTSUPPORT; ptrace(("%s: %p: ERROR: primitive not supported\n", MTP_MOD_NAME, mtp)); goto error; error: return n_error_ack(q, mtp, N_CONN_RES, err); } /* * N_DISCON_REQ: * ------------------------------------------------------------------- */ STATIC int n_discon_req(queue_t *q, struct mtp *mtp, mblk_t *mp) { int err; const N_discon_req_t *p = (typeof(p)) mp->b_rptr; if (mtp->prot.SERV_type == N_CLNS) goto notsupport; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto badprim; /* Currently there are only three states we can disconnect from. The first does not happen. Only the second one is normal. The third should occur during simulteneous diconnect only. */ switch (mtp_get_state(mtp)) { case NS_WCON_CREQ: mtp_set_state(mtp, NS_WACK_DREQ6); break; case NS_DATA_XFER: mtp_set_state(mtp, NS_WACK_DREQ9); break; case NS_IDLE: rare(); break; default: goto outstate; } return n_ok_ack(q, mtp, N_DISCON_REQ); badprim: err = -EMSGSIZE; ptrace(("%s: %p: ERROR: invalid primitive format\n", MTP_MOD_NAME, mtp)); goto error; outstate: err = NOUTSTATE; ptrace(("%s: %p: ERROR: would place i/f out of state\n", MTP_MOD_NAME, mtp)); goto error; notsupport: err = NNOTSUPPORT; ptrace(("%s: %p: ERROR: primitive not supported\n", MTP_MOD_NAME, mtp)); goto error; error: return n_error_ack(q, mtp, N_DISCON_REQ, err); } /* * N_DATA_REQ: * ------------------------------------------------------------------- */ STATIC int n_data_req(queue_t *q, struct mtp *mtp, mblk_t *mp) { const N_data_req_t *p = (typeof(p)) mp->b_rptr; const size_t dlen = msgdsize(mp); if (mtp->prot.SERV_type == N_CLNS) goto notsupport; if (mtp_get_state(mtp) == NS_IDLE) goto discard; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto einval; if ((1 << mtp_get_state(mtp)) & ~(NSF_DATA_XFER | NSF_WRES_RIND | NSF_WCON_RREQ)) goto outstate; if (p->DATA_xfer_flags) /* N_MORE_DATA_FLAG and N_RC_FLAG not supported yet. We could do N_MORE_DATA_FLAG pretty easily by accumulating the packet until the last data request is received, but this would be rather pointless for small MTP packet sizes. N_RC_FLAG cannot be supported until the DLPI link driver is done and zero-loss operation is completed. */ goto notsupport; if (dlen == 0 || dlen > mtp->prot.NSDU_size || dlen > mtp->prot.NIDU_size) goto baddata; return mtp_transfer_req(q, mtp, &mtp->dst, mtp->options.mp, mtp->options.sls, mp->b_cont); baddata: ptrace(("%s: %p: ERROR: bad data\n", MTP_MOD_NAME, mtp)); goto error; outstate: ptrace(("%s: %p: ERROR: would place i/f out of state\n", MTP_MOD_NAME, mtp)); goto error; einval: ptrace(("%s: %p: ERROR: invalid primitive format\n", MTP_MOD_NAME, mtp)); goto error; discard: ptrace(("%s: %p: ERROR: ignore in idle state\n", MTP_MOD_NAME, mtp)); return (QR_DONE); notsupport: ptrace(("%s: %p: ERROR: primitive not supported\n", MTP_MOD_NAME, mtp)); goto error; error: return m_error(q, mtp, -EPROTO); } /* * N_EXDATA_REQ: * ------------------------------------------------------------------- */ STATIC int n_exdata_req(queue_t *q, struct mtp *mtp, mblk_t *mp) { (void) mp; return m_error(q, mtp, -EPROTO); } /* * N_INFO_REQ: * ------------------------------------------------------------------- */ STATIC int n_info_req(queue_t *q, struct mtp *mtp, mblk_t *mp) { (void) mp; return n_info_ack(q, mtp); } /* * N_BIND_REQ: * ------------------------------------------------------------------- */ STATIC int n_bind_req(queue_t *q, struct mtp *mtp, mblk_t *mp) { int err; const N_bind_req_t *p = (typeof(p)) mp->b_rptr; struct mtp_addr src; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto badprim; if (mp->b_wptr < mp->b_rptr + p->ADDR_offset + p->ADDR_length) goto badprim; if (mp->b_wptr < mp->b_rptr + p->PROTOID_offset + p->PROTOID_length) goto badprim; if (mtp_get_state(mtp) != NS_UNBND) goto outstate; if (p->PROTOID_length) goto badaddr; if (!p->ADDR_length) goto noaddr; if (p->ADDR_length < sizeof(src)) goto badaddr; bcopy(mp->b_rptr + p->ADDR_offset, &src, sizeof(src)); if (src.family != AF_MTP) goto badaddr; if (!src.si || !src.pc) goto noaddr; if (src.si < 3 || mtp->cred.cr_uid != 0) goto access; mtp_set_state(mtp, NS_WACK_BREQ); return mtp_bind_req(q, mtp, &src, 0); access: err = NACCESS; ptrace(("%s: %p: ERROR: no priviledge for requested address\n", MTP_MOD_NAME, mtp)); goto error; noaddr: err = NNOADDR; ptrace(("%s: %p: ERROR: could not allocate address\n", MTP_MOD_NAME, mtp)); goto error; badaddr: err = NBADADDR; ptrace(("%s: %p: ERROR: requested address invalid\n", MTP_MOD_NAME, mtp)); goto error; outstate: err = NOUTSTATE; ptrace(("%s: %p: ERROR: would place i/f out of state\n", MTP_MOD_NAME, mtp)); goto error; badprim: err = -EMSGSIZE; ptrace(("%s: %p: ERROR: invalid primitive format\n", MTP_MOD_NAME, mtp)); goto error; error: return n_error_ack(q, mtp, N_BIND_REQ, err); } /* * N_UNBIND_REQ: * ------------------------------------------------------------------- */ STATIC int n_unbind_req(queue_t *q, struct mtp *mtp, mblk_t *mp) { int err; const N_unbind_req_t *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto badprim; if (mtp_get_state(mtp) != NS_IDLE) goto outstate; mtp_set_state(mtp, NS_WACK_UREQ); return mtp_unbind_req(q, mtp); outstate: err = NOUTSTATE; ptrace(("%s: %p: ERROR: would place i/f out of state\n", MTP_MOD_NAME, mtp)); goto error; badprim: err = -EMSGSIZE; ptrace(("%s: %p: ERROR: invalid primitive format\n", MTP_MOD_NAME, mtp)); goto error; error: return n_error_ack(q, mtp, N_UNBIND_REQ, err); } /* * N_UNITDATA_REQ: * ------------------------------------------------------------------- */ STATIC int n_unitdata_req(queue_t *q, struct mtp *mtp, mblk_t *mp) { int err; const N_unitdata_req_t *p = (typeof(p)) mp->b_rptr; const size_t dlen = msgdsize(mp); struct mtp_addr dst; if (mtp->prot.SERV_type != N_CLNS) goto notsupport; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto badprim; if (mp->b_wptr < mp->b_rptr + p->DEST_offset + p->DEST_length) goto badprim; if (mtp_get_state(mtp) != NS_IDLE) goto outstate; if (dlen == 0) goto baddata; if (dlen > mtp->prot.NSDU_size || dlen > mtp->prot.NIDU_size) goto baddata; if (!p->DEST_length) goto noaddr; if (p->DEST_length < sizeof(dst)) goto badaddr; bcopy(mp->b_rptr + p->DEST_length, &dst, sizeof(dst)); if (dst.family != AF_MTP) goto badaddr; if (!dst.si || !dst.pc) goto badaddr; if (dst.si < 3 && mtp->cred.cr_uid != 0) goto access; if (dst.si != mtp->src.si) goto badaddr; fixme(("Handle options correctly\n")); return mtp_transfer_req(q, mtp, &dst, mtp->options.mp, mtp->options.sls, mp->b_cont); access: err = NACCESS; ptrace(("%s: %p: ERROR: no priviledge for requested address\n", MTP_MOD_NAME, mtp)); goto error; badaddr: err = NBADADDR; ptrace(("%s: %p: ERROR: requested address invalid\n", MTP_MOD_NAME, mtp)); goto error; noaddr: err = NNOADDR; ptrace(("%s: %p: ERROR: could not allocate address\n", MTP_MOD_NAME, mtp)); goto error; baddata: err = NBADDATA; ptrace(("%s: %p: ERROR: invalid amount of data\n", MTP_MOD_NAME, mtp)); goto error; outstate: err = NOUTSTATE; ptrace(("%s: %p: ERROR: would place i/f out of state\n", MTP_MOD_NAME, mtp)); goto error; badprim: err = -EMSGSIZE; ptrace(("%s: %p: ERROR: invalid primitive format\n", MTP_MOD_NAME, mtp)); goto error; notsupport: err = NNOTSUPPORT; ptrace(("%s: %p: ERROR: primitive type not supported\n", MTP_MOD_NAME, mtp)); goto error; error: return n_error_ack(q, mtp, N_UNITDATA_REQ, err); } /* * N_OPTMGMT_REQ: * ------------------------------------------------------------------- */ STATIC int n_optmgmt_req(queue_t *q, struct mtp *mtp, mblk_t *mp) { int err; const N_optmgmt_req_t *p = (typeof(p)) mp->b_rptr; union N_qos_mtp *qos; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto badprim; if (mp->b_wptr < mp->b_rptr + p->QOS_offset + p->QOS_length) goto badprim; #ifdef NS_WACK_OPTREQ if (mtp_get_state(mtp) == NS_IDLE) mtp_set_state(mtp, NS_WACK_OPTREQ); #endif if (p->OPTMGMT_flags) /* Can't support DEFAULT_RC_SEL yet */ goto badflags; qos = (typeof(qos)) (mp->b_rptr + p->QOS_offset); if (p->QOS_length < sizeof(qos->n_qos_data)) goto badqostype; if (qos->n_qos_type != N_QOS_SEL_DATA_MTP) goto badqostype; if (qos->n_qos_data.sls > 255 && qos->n_qos_data.sls != -1UL) goto badqosparam; if (qos->n_qos_data.mp > 3 && qos->n_qos_data.mp != -1UL) goto badqosparam; mtp->options.sls = qos->n_qos_data.sls; mtp->options.mp = qos->n_qos_data.mp; return n_ok_ack(q, mtp, N_OPTMGMT_REQ); badqostype: err = NBADQOSTYPE; ptrace(("%s: %p: ERROR: invalid qos type\nn", MTP_MOD_NAME, mtp)); goto error; badqosparam: err = NBADQOSPARAM; ptrace(("%s: %p: ERROR: invalid qos parameter\nn", MTP_MOD_NAME, mtp)); goto error; badflags: err = NBADFLAG; ptrace(("%s: %p: ERROR: invalid flag\nn", MTP_MOD_NAME, mtp)); goto error; badprim: err = -EMSGSIZE; ptrace(("%s: %p: ERROR: invalid primitive format\n", MTP_MOD_NAME, mtp)); goto error; error: return n_error_ack(q, mtp, N_OPTMGMT_REQ, err); } /* * N_DATACK_REQ: * ------------------------------------------------------------------- */ STATIC int n_datack_req(queue_t *q, struct mtp *mtp, mblk_t *mp) { (void) q; (void) mp; /* We don't support DATACK yet. With zero loss operation we will. */ rare(); return (QR_DONE); } /* * N_RESET_REQ: * ------------------------------------------------------------------- */ STATIC int n_reset_req(queue_t *q, struct mtp *mtp, mblk_t *mp) { (void) q; (void) mp; todo(("Accept resets with reason from the user\n")); rare(); return (QR_DONE); } /* * N_RESET_RES: * ------------------------------------------------------------------- */ STATIC int n_reset_res(queue_t *q, struct mtp *mtp, mblk_t *mp) { (void) q; (void) mp; /* ignore. if the user wishes to respond to our reset indications that's fine. */ rare(); return (QR_DONE); } /* * ------------------------------------------------------------------------- * * Primitives received from below. * * ------------------------------------------------------------------------- */ /* * M_DATA * ----------------------------------- */ STATIC INLINE int mtp_data(queue_t *q, struct mtp *mtp, mblk_t *mp) { if (mtp->prot.SERV_type == N_CONS) return (QR_PASSALONG); swerr(); return (-EFAULT); } /* * MTP_OK_ACK: * ----------------------------------- * Simply translate the MTP_OK_ACK into a N_OK_ACK. */ STATIC INLINE int mtp_ok_ack(queue_t *q, struct mtp *mtp, mblk_t *mp) { int err; ulong prim; struct MTP_ok_ack *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto efault; switch (p->mtp_correct_prim) { case MTP_BIND_REQ: swerr(); prim = N_BIND_REQ; break; case MTP_UNBIND_REQ: prim = N_UNBIND_REQ; break; case MTP_CONN_REQ: prim = N_CONN_REQ; if ((err = n_ok_ack(q, mtp, prim)) < 0) return (err); return n_conn_con(q, mtp, 0, NULL, NULL); case MTP_DISCON_REQ: prim = N_DISCON_REQ; break; case MTP_ADDR_REQ: swerr(); prim = N_INFO_REQ; break; case MTP_INFO_REQ: swerr(); prim = N_INFO_REQ; break; case MTP_OPTMGMT_REQ: swerr(); prim = N_OPTMGMT_REQ; break; case MTP_TRANSFER_REQ: swerr(); prim = N_DATA_REQ; break; default: swerr(); prim = 0; break; } return n_ok_ack(q, mtp, prim); efault: pswerr(("%s: %p: SWERR: invalid primitive from below\n", MTP_MOD_NAME, mtp)); return (-EFAULT); } /* * MTP_ERROR_ACK: * ----------------------------------- * Simply translate the MTP_ERROR_ACK into a N_ERROR_ACK. */ STATIC INLINE int mtp_error_ack(queue_t *q, struct mtp *mtp, mblk_t *mp) { int err; ulong prim; struct MTP_error_ack *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto efault; switch (p->mtp_primitive) { case MTP_BIND_REQ: prim = N_BIND_REQ; break; case MTP_UNBIND_REQ: prim = N_UNBIND_REQ; break; case MTP_CONN_REQ: prim = N_CONN_REQ; break; case MTP_DISCON_REQ: prim = N_DISCON_REQ; break; case MTP_ADDR_REQ: swerr(); prim = N_INFO_REQ; break; case MTP_INFO_REQ: prim = N_INFO_REQ; break; case MTP_OPTMGMT_REQ: prim = N_OPTMGMT_REQ; break; case MTP_TRANSFER_REQ: swerr(); prim = N_DATA_REQ; break; default: swerr(); prim = 0; break; } switch (p->mtp_mtpi_error) { case MSYSERR: err = -p->mtp_unix_error; break; case MACCESS: err = NACCESS; break; case MBADADDR: err = NBADADDR; break; case MNOADDR: err = NNOADDR; break; case MBADPRIM: err = -EINVAL; break; case MOUTSTATE: err = NOUTSTATE; break; case MNOTSUPP: err = NNOTSUPPORT; break; case MBADFLAG: err = NBADFLAG; break; case MBADOPT: err = NBADOPT; break; default: swerr(); err = -EFAULT; break; } return n_error_ack(q, mtp, prim, err); efault: pswerr(("%s: %p: SWERR: invalid primitive from below\n", MTP_MOD_NAME, mtp)); return (-EFAULT); } /* * MTP_BIND_ACK: * ----------------------------------- * Translate the MTP_BIND_ACK into a N_BIND_ACK. */ STATIC INLINE int mtp_bind_ack(queue_t *q, struct mtp *mtp, mblk_t *mp) { struct MTP_bind_ack *p = (typeof(p)) mp->b_rptr; struct mtp_addr *add = NULL; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto efault; if (mp->b_wptr < mp->b_rptr + p->mtp_addr_offset + p->mtp_addr_length) goto efault; if (p->mtp_addr_length == sizeof(*add)) add = (typeof(add)) (mp->b_rptr + p->mtp_addr_offset); return n_bind_ack(q, mtp, add); efault: pswerr(("%s: %p: SWERR: invalid primitive from below\n", MTP_MOD_NAME, mtp)); return (-EFAULT); } /* * MTP_ADDR_ACK: * ----------------------------------- * Simply translate MTP_ADDR_ACK to N_ADDR_ACK. */ STATIC INLINE int mtp_addr_ack(queue_t *q, struct mtp *mtp, mblk_t *mp) { struct MTP_addr_ack *p = (typeof(p)) mp->b_rptr; struct mtp_addr *loc = NULL, *rem = NULL; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto efault; if (mp->b_wptr < mp->b_rptr + p->mtp_loc_offset + p->mtp_loc_length) goto efault; if (mp->b_wptr < mp->b_rptr + p->mtp_rem_offset + p->mtp_rem_length) goto efault; if (p->mtp_loc_length == sizeof(*loc)) loc = (typeof(loc)) (mp->b_rptr + p->mtp_loc_offset); if (p->mtp_rem_length == sizeof(*rem)) rem = (typeof(rem)) (mp->b_rptr + p->mtp_rem_offset); return (QR_DONE); efault: pswerr(("%s: %p: SWERR: invalid primitive from below\n", MTP_MOD_NAME, mtp)); return (-EFAULT); } /* * MTP_INFO_ACK: * ----------------------------------- * Simply translate MTP_INFO_ACK to N_INFO_ACK. */ STATIC INLINE int mtp_info_ack(queue_t *q, struct mtp *mtp, mblk_t *mp) { struct MTP_info_ack *p = (typeof(p)) mp->b_rptr; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto efault; if (mp->b_wptr < mp->b_rptr + p->mtp_addr_offset + p->mtp_addr_length) goto efault; mtp->prot.NSDU_size = p->mtp_msu_size; mtp->prot.NIDU_size = p->mtp_msu_size; mtp->prot.ADDR_size = p->mtp_addr_size; switch (p->mtp_serv_type) { case M_COMS: mtp->prot.SERV_type = N_CONS; mtp->prot.CDATA_size = p->mtp_msu_size; mtp->prot.DDATA_size = p->mtp_msu_size; break; case M_CLMS: mtp->prot.SERV_type = N_CLNS; mtp->prot.CDATA_size = -2UL; mtp->prot.DDATA_size = -2UL; break; default: swerr(); break; } return n_info_ack(q, mtp); efault: pswerr(("%s: %p: SWERR: invalid primitive from below\n", MTP_MOD_NAME, mtp)); return (-EFAULT); } /* * MTP_OPTMGMT_ACK: * ----------------------------------- */ STATIC INLINE int mtp_optmgmt_ack(queue_t *q, struct mtp *mtp, mblk_t *mp) { swerr(); return (-EFAULT); } /* * MTP_TRANSFER_IND: * ----------------------------------- * Translate MTP_TRANSFER_IND into N_OPTDATA_IND or N_UNITDATA_IND. */ STATIC INLINE int mtp_transfer_ind(queue_t *q, struct mtp *mtp, mblk_t *mp) { int err; struct MTP_transfer_ind *p = (typeof(p)) mp->b_rptr; struct mtp_addr *src; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto efault; if (mp->b_wptr < mp->b_rptr + p->mtp_srce_offset + p->mtp_srce_length) goto efault; if (p->mtp_srce_length != sizeof(*src)) goto efault; src = (typeof(src)) (mp->b_rptr + p->mtp_srce_offset); switch (mtp->prot.SERV_type) { case N_CONS: /* N_DATA_IND */ if ((err = n_data_ind(q, mtp, 0, mp->b_cont)) < 0) goto error; return (QR_TRIMMED); case N_CLNS: /* N_UNITDATA_IND */ if ((err = n_unitdata_ind(q, mtp, src, &mtp->src, mp->b_cont)) < 0) goto error; return (QR_TRIMMED); } swerr(); return (-EFAULT); efault: pswerr(("%s: %p: SWERR: invalid primitive from below\n", MTP_MOD_NAME, mtp)); return (-EFAULT); error: return (err); } /* * MTP_PAUSE_IND: * ----------------------------------- * Translate MTP_PAUSE_IND into N_UDERROR_IND or N_DISCON_IND. */ STATIC INLINE int mtp_pause_ind(queue_t *q, struct mtp *mtp, mblk_t *mp) { struct MTP_pause_ind *p = (typeof(p)) mp->b_rptr; struct mtp_addr *dst; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto efault; if (mp->b_wptr < mp->b_rptr + p->mtp_addr_offset + p->mtp_addr_length) goto efault; if (p->mtp_addr_length != sizeof(*dst)) goto efault; dst = (typeof(dst)) (mp->b_rptr + p->mtp_addr_offset); switch (mtp->prot.SERV_type) { case N_CONS: /* N_DISCON_IND */ return n_discon_ind(q, mtp, N_PROVIDER, N_MTP_DEST_PROHIBITED, 0, NULL, mp->b_cont); case N_CLNS: { struct mtp_addr *dst; dst = (typeof(dst)) (mp->b_rptr + p->mtp_addr_length); /* N_UDERROR_IND */ return n_uderror_ind(q, mtp, dst, mp->b_cont, N_MTP_DEST_PROHIBITED); } } swerr(); return (-EFAULT); efault: pswerr(("%s: %p: SWERR: invalid primitive from below\n", MTP_MOD_NAME, mtp)); return (-EFAULT); } /* * MTP_RESUME_IND: * ----------------------------------- * Translate MTP_RESUME_IND. */ STATIC INLINE int mtp_resume_ind(queue_t *q, struct mtp *mtp, mblk_t *mp) { /* discard */ return (QR_DONE); } /* * MTP_STATUS_IND: * ----------------------------------- * Translate MTP_STATUS_IND into N_UDERROR_IND or N_RESET_IND or * N_DISCON_IND. */ STATIC INLINE int mtp_status_ind(queue_t *q, struct mtp *mtp, mblk_t *mp) { struct MTP_status_ind *p = (typeof(p)) mp->b_rptr; ulong type; ulong status; ulong error; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto efault; type = p->mtp_type; status = p->mtp_status; switch (type) { case MTP_STATUS_TYPE_UPU: switch (status) { case MTP_STATUS_UPU_UNKNOWN: error = N_MTP_USER_PART_UNKNOWN; break; case MTP_STATUS_UPU_UNEQUIPPED: error = N_MTP_USER_PART_UNEQUIPPED; break; case MTP_STATUS_UPU_INACCESSIBLE: error = N_MTP_USER_PART_UNAVAILABLE; break; default: swerr(); return (-EFAULT); } break; case MTP_STATUS_TYPE_CONG: switch (status) { case MTP_STATUS_CONGESTION_LEVEL0: error = N_MTP_DEST_CONGESTED(0); break; case MTP_STATUS_CONGESTION_LEVEL1: error = N_MTP_DEST_CONGESTED(1); break; case MTP_STATUS_CONGESTION_LEVEL2: error = N_MTP_DEST_CONGESTED(2); break; case MTP_STATUS_CONGESTION_LEVEL3: error = N_MTP_DEST_CONGESTED(3); break; case MTP_STATUS_CONGESTION: error = N_MTP_DEST_CONGESTED(4); break; default: swerr(); return (-EFAULT); } break; default: swerr(); return (-EFAULT); } switch (mtp->prot.SERV_type) { case N_CONS: switch (type) { case MTP_STATUS_TYPE_UPU: /* N_DISCON_IND */ return n_discon_ind(q, mtp, N_USER, error, 0, NULL, mp->b_cont); case MTP_STATUS_TYPE_CONG: /* N_RESET_IND */ return n_reset_ind(q, mtp, N_PROVIDER, error); } break; case N_CLNS: { /* N_UDERROR_IND */ struct mtp_addr *dst; dst = (typeof(dst)) (mp->b_rptr + p->mtp_addr_length); return n_uderror_ind(q, mtp, dst, mp->b_cont, error); } } swerr(); return (-EFAULT); efault: pswerr(("%s: %p: SWERR: invalid primitive from below\n", MTP_MOD_NAME, mtp)); return (-EFAULT); } /* * MTP_RESTART_BEGINS_IND: * ----------------------------------- * Translate MTP_RESTART_BEGINS_IND into N_UDERROR_IND or N_DISCON_IND. */ STATIC INLINE int mtp_restart_begins_ind(queue_t *q, struct mtp *mtp, mblk_t *mp) { struct MTP_restart_begins_ind *p = (typeof(p)) mp->b_rptr; ulong error = N_MTP_RESTARTING; if (mp->b_wptr < mp->b_rptr + sizeof(*p)) goto efault; switch (mtp->prot.SERV_type) { case N_CONS: /* N_DISCON_IND */ return n_discon_ind(q, mtp, N_PROVIDER, error, 0, NULL, mp->b_cont); case N_CLNS: { /* N_UDERROR_IND */ struct mtp_addr *dst = NULL; return n_uderror_ind(q, mtp, dst, mp->b_cont, error); } } swerr(); return (-EFAULT); efault: pswerr(("%s: %p: SWERR: invalid primitive from below\n", MTP_MOD_NAME, mtp)); return (-EFAULT); } /* * MTP_RESTART_COMPLETE_IND: * ----------------------------------- * Translate MTP_RESTART_COMPLETE_IND. */ STATIC INLINE int mtp_restart_complete_ind(queue_t *q, struct mtp *mtp, mblk_t *mp) { /* discard */ return (QR_DONE); } /* * ========================================================================= * * STREAMS Message Handling * * ========================================================================= */ #if 0 /* * ------------------------------------------------------------------------- * * M_IOCTL Handling * * ------------------------------------------------------------------------- */ STATIC int mtp_w_ioctl(queue_t *q, mblk_t *mp) { struct mtp *mtp = MTP_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: ERROR: Unsupported STREAMS ioctl %d\n", MTP_MOD_NAME, nr)); ret = -EINVAL; break; default: ptrace(("%s: ERROR: Unsupported STREAMS ioctl %d\n", MTP_MOD_NAME, nr)); ret = -EOPNOTSUPP; break; } break; case MTP_IOC_MAGIC: ret = (QR_PASSALONG); break; default: ret = (QR_PASSALONG); 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); } #endif /* * ------------------------------------------------------------------------- * * M_PROTO, M_PCPROTO Handling * * ------------------------------------------------------------------------- */ /* * Primitives from NPI to MTP. * ----------------------------------- */ STATIC int mtp_w_proto(queue_t *q, mblk_t *mp) { int rtn; ulong prim; struct mtp *mtp = MTP_PRIV(q); ulong oldstate = mtp_get_state(mtp); /* Fast Path */ if ((prim = *((ulong *) mp->b_rptr)) == N_DATA_REQ) { printd(("%s: %p: -> N_DATA_REQ [%d]\n", MTP_MOD_NAME, mtp, msgdsize(mp->b_cont))); if ((rtn = n_data_req(q, mtp, mp))) mtp_set_state(mtp, oldstate); return (rtn); } switch (prim) { case N_CONN_REQ: printd(("%s: %p: -> N_CONN_REQ\n", MTP_MOD_NAME, mtp)); rtn = n_conn_req(q, mtp, mp); break; case N_CONN_RES: printd(("%s: %p: -> N_CONN_RES\n", MTP_MOD_NAME, mtp)); rtn = n_conn_res(q, mtp, mp); break; case N_DISCON_REQ: printd(("%s: %p: -> N_DISCON_REQ\n", MTP_MOD_NAME, mtp)); rtn = n_discon_req(q, mtp, mp); break; case N_DATA_REQ: printd(("%s: %p: -> N_DATA_REQ\n", MTP_MOD_NAME, mtp)); rtn = n_data_req(q, mtp, mp); break; case N_EXDATA_REQ: printd(("%s: %p: -> N_EXDATA_REQ\n", MTP_MOD_NAME, mtp)); rtn = n_exdata_req(q, mtp, mp); break; case N_INFO_REQ: printd(("%s: %p: -> N_INFO_REQ\n", MTP_MOD_NAME, mtp)); rtn = n_info_req(q, mtp, mp); break; case N_BIND_REQ: printd(("%s: %p: -> N_BIND_REQ\n", MTP_MOD_NAME, mtp)); rtn = n_bind_req(q, mtp, mp); break; case N_UNBIND_REQ: printd(("%s: %p: -> N_UNBIND_REQ\n", MTP_MOD_NAME, mtp)); rtn = n_unbind_req(q, mtp, mp); break; case N_UNITDATA_REQ: printd(("%s: %p: -> N_UNITDATA_REQ\n", MTP_MOD_NAME, mtp)); rtn = n_unitdata_req(q, mtp, mp); break; case N_OPTMGMT_REQ: printd(("%s: %p: -> N_OPTMGMT_REQ\n", MTP_MOD_NAME, mtp)); rtn = n_optmgmt_req(q, mtp, mp); break; case N_DATACK_REQ: printd(("%s: %p: -> N_DATACK_REQ\n", MTP_MOD_NAME, mtp)); rtn = n_datack_req(q, mtp, mp); break; case N_RESET_REQ: printd(("%s: %p: -> N_RESET_REQ\n", MTP_MOD_NAME, mtp)); rtn = n_reset_req(q, mtp, mp); break; case N_RESET_RES: printd(("%s: %p: -> N_RESET_RES\n", MTP_MOD_NAME, mtp)); rtn = n_reset_res(q, mtp, mp); break; default: swerr(); rtn = -EOPNOTSUPP; break; } if (rtn < 0) mtp_set_state(mtp, oldstate); return (rtn); } /* * Primitives from MTP to NPI. * ----------------------------------- */ STATIC int mtp_r_proto(queue_t *q, mblk_t *mp) { int rtn; ulong prim; struct mtp *mtp = MTP_PRIV(q); ulong oldstate = mtp_get_state(mtp); /* Fast Path */ if ((prim = *((ulong *) mp->b_rptr)) == MTP_TRANSFER_IND) { printd(("%s: %p: MTP_TRANSFER_IND [%d] <-\n", MTP_MOD_NAME, mtp, msgdsize(mp->b_cont))); if ((rtn = mtp_transfer_ind(q, mtp, mp)) < 0) mtp_set_state(mtp, oldstate); return (rtn); } switch (prim) { case MTP_OK_ACK: printd(("%s: %p: MTP_OK_ACK <-\n", MTP_MOD_NAME, mtp)); rtn = mtp_ok_ack(q, mtp, mp); break; case MTP_ERROR_ACK: printd(("%s: %p: MTP_ERROR_ACK <-\n", MTP_MOD_NAME, mtp)); rtn = mtp_error_ack(q, mtp, mp); break; case MTP_BIND_ACK: printd(("%s: %p: MTP_BIND_ACK <-\n", MTP_MOD_NAME, mtp)); rtn = mtp_bind_ack(q, mtp, mp); break; case MTP_ADDR_ACK: printd(("%s: %p: MTP_ADDR_ACK <-\n", MTP_MOD_NAME, mtp)); rtn = mtp_addr_ack(q, mtp, mp); break; case MTP_INFO_ACK: printd(("%s: %p: MTP_INFO_ACK <-\n", MTP_MOD_NAME, mtp)); rtn = mtp_info_ack(q, mtp, mp); break; case MTP_OPTMGMT_ACK: printd(("%s: %p: MTP_OPTMGMT_ACK <-\n", MTP_MOD_NAME, mtp)); rtn = mtp_optmgmt_ack(q, mtp, mp); break; case MTP_TRANSFER_IND: printd(("%s: %p: MTP_TRANSFER_IND <-\n", MTP_MOD_NAME, mtp)); rtn = mtp_transfer_ind(q, mtp, mp); break; case MTP_PAUSE_IND: printd(("%s: %p: MTP_PAUSE_IND <-\n", MTP_MOD_NAME, mtp)); rtn = mtp_pause_ind(q, mtp, mp); break; case MTP_RESUME_IND: printd(("%s: %p: MTP_RESUME_IND <-\n", MTP_MOD_NAME, mtp)); rtn = mtp_resume_ind(q, mtp, mp); break; case MTP_STATUS_IND: printd(("%s: %p: MTP_STATUS_IND <-\n", MTP_MOD_NAME, mtp)); rtn = mtp_status_ind(q, mtp, mp); break; case MTP_RESTART_BEGINS_IND: printd(("%s: %p: MTP_RESTART_BEGINS_IND <-\n", MTP_MOD_NAME, mtp)); rtn = mtp_restart_begins_ind(q, mtp, mp); break; case MTP_RESTART_COMPLETE_IND: printd(("%s: %p: MTP_RESTART_COMPLETE_IND <-\n", MTP_MOD_NAME, mtp)); rtn = mtp_restart_complete_ind(q, mtp, mp); break; default: swerr(); rtn = -EOPNOTSUPP; break; } if (rtn < 0) mtp_set_state(mtp, oldstate); return (rtn); } /* * ------------------------------------------------------------------------- * * M_DATA Handling * * ------------------------------------------------------------------------- */ STATIC int mtp_w_data(queue_t *q, mblk_t *mp) { struct mtp *mtp = MTP_PRIV(q); /* data from above */ printd(("%s: %p: -> M_DATA [%d]\n", MTP_MOD_NAME, mtp, msgdsize(mp))); return n_data(q, mtp, mp); } STATIC int mtp_r_data(queue_t *q, mblk_t *mp) { struct mtp *mtp = MTP_PRIV(q); /* data from below */ printd(("%s: %p: M_DATA [%d] <-\n", MTP_MOD_NAME, mtp, msgdsize(mp))); return mtp_data(q, mtp, mp); } /* * ========================================================================= * * PUT and SRV * * ========================================================================= */ STATIC INLINE int mtp_w_prim(queue_t *q, mblk_t *mp) { /* Fast Path */ if (mp->b_datap->db_type == M_DATA) return mtp_w_data(q, mp); switch (mp->b_datap->db_type) { case M_DATA: return mtp_w_data(q, mp); case M_PROTO: case M_PCPROTO: return mtp_w_proto(q, mp); case M_FLUSH: return ss7_w_flush(q, mp); #if 0 case M_IOCTL: return mtp_w_ioctl(q, mp); #endif } return (QR_PASSALONG); } STATIC INLINE int mtp_r_prim(queue_t *q, mblk_t *mp) { /* Fast Path */ if (mp->b_datap->db_type == M_DATA) return mtp_r_data(q, mp); switch (mp->b_datap->db_type) { case M_DATA: return mtp_r_data(q, mp); case M_PROTO: case M_PCPROTO: return mtp_r_proto(q, mp); case M_FLUSH: return ss7_r_flush(q, mp); #if 0 case M_IOCACK: return mtp_r_iocack(q, mp); case M_IOCNAK: return mtp_r_iocnak(q, mp); #endif } return (QR_PASSALONG); } /* * ========================================================================= * * OPEN and CLOSE * * ========================================================================= */ /* * OPEN * ------------------------------------------------------------------------- */ STATIC int mtp_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp) { 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 mtp *mtp; /* test for multiple push */ for (mtp = mtp_opens; mtp; mtp = mtp->next) { if (mtp->u.dev.cmajor == cmajor && mtp->u.dev.cminor == cminor) { MOD_DEC_USE_COUNT; return (ENXIO); } } if (!(mtp_alloc_priv(q, &mtp_opens, devp, crp))) { MOD_DEC_USE_COUNT; return (ENOMEM); } #if 0 /* generate immediate information request */ if ((err = sdt_info_req(q, mtp)) < 0) { mtp_free_priv(q); MOD_DEC_USE_COUNT; return (-err); } #endif return (0); } MOD_DEC_USE_COUNT; return EIO; } /* * CLOSE * ------------------------------------------------------------------------- */ STATIC int mtp_close(queue_t *q, int flag, cred_t *crp) { (void) flag; (void) crp; mtp_free_priv(q); MOD_DEC_USE_COUNT; return (0); } /* * ========================================================================= * * Private Structure allocation, deallocation and cache * * ========================================================================= */ STATIC kmem_cache_t *mtp_priv_cachep = NULL; STATIC int mtp_init_caches(void) { if (!mtp_priv_cachep && !(mtp_priv_cachep = kmem_cache_create ("mtp_priv_cachep", sizeof(struct mtp), 0, SLAB_HWCACHE_ALIGN, NULL, NULL))) { cmn_err(CE_PANIC, "%s: Cannot allocate mtp_priv_cachep", __FUNCTION__); return (-ENOMEM); } else printd(("%s: initialized module private structure cace\n", MTP_MOD_NAME)); return (0); } STATIC void mtp_term_caches(void) { if (mtp_priv_cachep) { if (kmem_cache_destroy(mtp_priv_cachep)) cmn_err(CE_WARN, "%s: did not destroy mtp_priv_cachep", __FUNCTION__); else printd(("%s: destroyed mtp_priv_cachep\n", MTP_MOD_NAME)); } return; } STATIC struct mtp *mtp_alloc_priv(queue_t *q, struct mtp **mtpp, dev_t *devp, cred_t *crp) { struct mtp *mtp; if ((mtp = kmem_cache_alloc(mtp_priv_cachep, SLAB_ATOMIC))) { printd(("%s: allocated module private structure\n", MTP_MOD_NAME)); bzero(mtp, sizeof(*mtp)); mtp_get(mtp); /* first get */ mtp->u.dev.cmajor = getmajor(*devp); mtp->u.dev.cminor = getminor(*devp); mtp->cred = *crp; (mtp->oq = RD(q))->q_ptr = mtp_get(mtp); (mtp->iq = WR(q))->q_ptr = mtp_get(mtp); lis_spin_lock_init(&mtp->qlock, "mtp-queue-lock"); mtp->o_prim = &mtp_r_prim; mtp->i_prim = &mtp_w_prim; mtp->o_wakeup = NULL; mtp->i_wakeup = NULL; mtp->i_state = NS_UNBND; mtp->i_style = LMI_STYLE1; mtp->i_version = 1; lis_spin_lock_init(&mtp->lock, "mtp-priv-lock"); if ((mtp->next = *mtpp)) mtp->next->prev = &mtp->next; mtp->prev = mtpp; *mtpp = mtp_get(mtp); printd(("%s: linked module private structure\n", MTP_MOD_NAME)); mtp->prot.PRIM_type = N_INFO_ACK; mtp->prot.NSDU_size = -1UL; mtp->prot.ENSDU_size = -2UL; mtp->prot.CDATA_size = -2UL; mtp->prot.DDATA_size = -2UL; mtp->prot.ADDR_size = sizeof(struct mtp_addr); mtp->prot.OPTIONS_flags = 0; mtp->prot.NIDU_size = -1UL; mtp->prot.SERV_type = N_CLNS; mtp->prot.CURRENT_state = NS_UNBND; mtp->prot.PROVIDER_type = N_SNICFP; mtp->prot.NODU_size = 279; mtp->prot.NPI_version = N_VERSION_2; printd(("%s: setting module private structure defaults\n", MTP_MOD_NAME)); } else ptrace(("%s: ERROR: Could not allocate module private structure\n", MTP_MOD_NAME)); return (mtp); } STATIC void mtp_free_priv(queue_t *q) { struct mtp *mtp = MTP_PRIV(q); int flags = 0; ensure(mtp, return); lis_spin_lock_irqsave(&mtp->lock, &flags); { ss7_unbufcall((str_t *) mtp); if ((*mtp->prev = mtp->next)) mtp->next->prev = mtp->prev; mtp->next = NULL; mtp->prev = &mtp->next; mtp_put(mtp); mtp->oq->q_ptr = NULL; flushq(mtp->oq, FLUSHALL); mtp->oq = NULL; mtp_put(mtp); mtp->iq->q_ptr = NULL; flushq(mtp->iq, FLUSHALL); mtp->iq = NULL; mtp_put(mtp); } lis_spin_unlock_irqrestore(&mtp->lock, &flags); mtp_put(mtp); /* final put */ } STATIC struct mtp *mtp_get(struct mtp *mtp) { atomic_inc(&mtp->refcnt); return (mtp); } STATIC void mtp_put(struct mtp *mtp) { if (atomic_dec_and_test(&mtp->refcnt)) { kmem_cache_free(mtp_priv_cachep, mtp); printd(("%s: %p: freed mtp private structure\n", MTP_MOD_NAME, mtp)); } } /* * ========================================================================= * * LiS Module Initialization (For unregistered driver.) * * ========================================================================= */ STATIC int mtp_initialized = 0; STATIC void mtp_init(void) { unless(mtp_initialized > 0, return); cmn_err(CE_NOTE, MTP_BANNER); /* console splash */ if ((mtp_initialized = mtp_init_caches())) { cmn_err(CE_PANIC, "%s: ERROR: could not allocate caches", MTP_MOD_NAME); } else if (!(mtp_initialized = lis_register_strmod(&mtp_info, MTP_MOD_NAME)) < 0) { cmn_err(CE_WARN, "%s: couldn't register module", MTP_MOD_NAME); mtp_term_caches(); } return; } STATIC void mtp_terminate(void) { ensure(mtp_initialized > 0, return); if ((mtp_initialized = lis_unregister_strmod(&mtp_info)) < 0) { cmn_err(CE_PANIC, "%s: couldn't unregister module", MTP_MOD_NAME); } else { mtp_term_caches(); } return; } /* * ========================================================================= * * Kernel Module Initialization * * ========================================================================= */ int init_module(void) { mtp_init(); if (mtp_initialized < 0) return mtp_initialized; return (0); } void cleanup_module(void) { mtp_terminate(); return; }
|
|||||||||||||||||||||||||||
OpenSS7 SS7 for the Common Man |
Home | Overview | Status | News | Documentation | Resources | About | ||||||||||||||||||||
© Copyright 1997-2004,OpenSS7 Corporation, All Rights Reserved. |