📄 sdlm.c
字号:
{ int err; size_t mlen = mp->b_wptr - mp->b_rptr; lmi_attach_req_t *m = ((typeof(m)) mp->b_rptr); if (mlen < sizeof(*m) || mlen < 2 * sizeof(ulong)) goto lprotoshort; if (q->q_next) goto loutstate; { struct dl *dl = DL_PRIV(q); struct sd *sd; ulong ppa = *((ulong *) &m->lmi_ppa); for (sd = master.sd.list; sd && sd->ppa != ppa; sd = sd->next) ; if (!sd || sd->iq->q_next) goto lbadppa; /* link queues together */#ifdef LFS weldq(dl->iq, sd->oq, sd->iq, dl->oq, NULL, 0, dl->iq);#else dl->iq->q_next = sd->oq; sd->iq->q_next = dl->oq;#endif return lmi_ok_ack_reply(q, mp, LMI_ATTACH_REQ, LMI_DISABLED); } lbadppa: err = LMI_BADPPA; ptrace(("ERROR: PPA in use\n")); goto error; loutstate: err = LMI_OUTSTATE; ptrace(("ERROR: would place i/f out of state\n")); goto error; lprotoshort: err = LMI_PROTOSHORT; ptrace(("ERROR: proto block to short\n")); goto error; error: return lmi_error_ack_reply(q, mp, LMI_ATTACH_REQ, LMI_UNATTACHED, err);}/* * LMI_DETACH_REQ: * ----------------------------------- */STATIC INLINE intlmi_detach_req(queue_t *q, mblk_t *mp){ int err; size_t mlen = mp->b_wptr - mp->b_rptr; lmi_detach_req_t *m = ((typeof(m)) mp->b_rptr); if (mlen < sizeof(*m)) goto lprotoshort; if (!q->q_next) goto loutstate; { lmi_ok_ack_t *p; struct dl *dl = DL_PRIV(q); struct sd *sd = SD_PRIV(q->q_next); /* disconnect them */#ifdef LFS unweldq(dl->iq, sd->oq, sd->iq, dl->oq, NULL, 0, dl->iq);#else dl->iq->q_next = NULL; sd->iq->q_next = NULL;#endif mp->b_wptr = mp->b_rptr; p = (typeof(p)) mp->b_wptr; mp->b_wptr += sizeof(*p); p->lmi_primitive = LMI_OK_ACK; p->lmi_correct_primitive = LMI_DETACH_REQ; p->lmi_state = LMI_UNATTACHED; qreply(q, mp); return (0); } loutstate: err = LMI_OUTSTATE; ptrace(("ERROR: would place i/f out of state\n")); goto error; lprotoshort: err = LMI_PROTOSHORT; ptrace(("ERROR: proto block too short\n")); goto error; error: return lmi_error_ack_reply(q, mp, LMI_DETACH_REQ, LMI_UNATTACHED, err);}/* * ========================================================================= * * STREAMS Message Handling * * ========================================================================= *//* * ------------------------------------------------------------------------- * * M_PROTO, M_PCPROTO Handling * * ------------------------------------------------------------------------- */STATIC intdl_w_proto(queue_t *q, mblk_t *mp){ long prim = *((long *) mp->b_rptr); switch (prim) { case LMI_ATTACH_REQ: return ((int) lmi_attach_req(q, mp)); case LMI_DETACH_REQ: return ((int) lmi_detach_req(q, mp)); case LMI_INFO_REQ: case LMI_ENABLE_REQ: case LMI_DISABLE_REQ: case LMI_OPTMGMT_REQ: if (q->q_next) { putnext(q, mp); return ((int) (0)); } ptrace(("ERROR: would place i/f out of state\n")); return lmi_error_ack_reply(q, mp, prim, LMI_UNATTACHED, LMI_OUTSTATE); case SDL_BITS_FOR_TRANSMISSION_REQ: case SDL_CONNECT_REQ: case SDL_DISCONNECT_REQ: if (q->q_next) { putnext(q, mp); return ((int) (0)); } return ((int) m_error_reply(q, mp, EPIPE)); default: freemsg(mp); return ((int) m_error_reply(q, mp, EPROTO)); }}/* * ------------------------------------------------------------------------- * * M_IOCTL Handling * * ------------------------------------------------------------------------- */STATIC intdl_w_ioctl(queue_t *q, mblk_t *mp){ struct dl *dl = DL_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); int ret = 0; (void) dl; (void) size; (void) count; switch (type) { case _IOC_TYPE(__SID): { psw_t flags; struct sd *sd, **spp; struct linkblk *lb = (struct linkblk *) arg; if (!lb) { swerr(); ret = -EINVAL; break; } switch (nr) { case _IOC_NR(I_PLINK): ptrace(("%s: %p: I_PLINK\n", DRV_NAME, dl)); if (iocp->ioc_cr->cr_uid != 0) { ptrace(("%s: %p: ERROR: Non-root attempt to I_PLINK\n", DRV_NAME, dl)); ret = -EPERM; break; } case _IOC_NR(I_LINK): ptrace(("%s: %p: I_LINK\n", DRV_NAME, dl)); MOD_INC_USE_COUNT; /* keep module from unloading */ spin_lock_irqsave(&master.lock, flags); { /* place in list in ascending index order */ for (spp = &master.sd.list; *spp && (*spp)->u.mux.index < lb->l_index; spp = &(*spp)->next) ; if ((sd = sdlm_alloc_sd(lb->l_qbot, spp, lb->l_index, iocp->ioc_cr))) { spin_unlock_irqrestore(&master.lock, flags); break; } MOD_DEC_USE_COUNT; ret = -ENOMEM; } spin_unlock_irqrestore(&master.lock, flags); break; case _IOC_NR(I_PUNLINK): ptrace(("%s: %p: I_PUNLINK\n", DRV_NAME, dl)); if (iocp->ioc_cr->cr_uid != 0) { ptrace(("%s: %p: ERROR: Non-root attempt to I_PUNLINK\n", DRV_NAME, dl)); ret = -EPERM; break; } case _IOC_NR(I_UNLINK): ptrace(("%s: %p: I_UNLINK\n", DRV_NAME, dl)); spin_lock_irqsave(&master.lock, flags); { for (sd = master.sd.list; sd; sd = sd->next) if (sd->u.mux.index == lb->l_index) break; if (!sd) { ret = -EINVAL; ptrace(("%s: %p: ERROR: Couldn't find I_UNLINK muxid\n", DRV_NAME, dl)); spin_unlock_irqrestore(&master.lock, flags); break; } sdlm_free_sd(sd->iq); MOD_DEC_USE_COUNT; } spin_unlock_irqrestore(&master.lock, flags); break; default: case _IOC_NR(I_STR): ptrace(("%s: %p: ERROR: Unspported STREAMS ioctl %c, %d\n", DRV_NAME, dl, (char) type, nr)); ret = -EOPNOTSUPP; break; } break; } default: ptrace(("%s: %p: ERROR: Unsupported ioctl %c, %d\n", DRV_NAME, dl, (char) type, nr)); ret = -EOPNOTSUPP; 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);}/* * UPPER MUX Queues * ----------------------------------- */STATIC streamscall intdl_r_prim(queue_t *q, mblk_t *mp){ switch (mp->b_datap->db_type) { case M_FLUSH: return ss7_r_flush(q, mp); default: return (QR_PASSFLOW); }}STATIC streamscall intdl_w_prim(queue_t *q, mblk_t *mp){ switch (mp->b_datap->db_type) { case M_FLUSH: return ss7_w_flush(q, mp); case M_PROTO: case M_PCPROTO: return dl_w_proto(q, mp); case M_IOCTL: return dl_w_ioctl(q, mp); default: case M_DATA: return (QR_PASSFLOW); }}/* * LOWER MUX Queues * ----------------------------------- */STATIC streamscall intsd_r_prim(queue_t *q, mblk_t *mp){ switch (mp->b_datap->db_type) { case M_FLUSH: return ss7_r_flush(q, mp); default: return (QR_PASSFLOW); }}STATIC streamscall intsd_w_prim(queue_t *q, mblk_t *mp){ switch (mp->b_datap->db_type) { case M_FLUSH: return ss7_w_flush(q, mp); default: return (QR_PASSFLOW); }}/* * ========================================================================= * * OPEN and CLOSE * * ========================================================================= */STATIC major_t sdlm_majors[SDLM_CMAJORS] = { SDLM_CMAJOR_0, };/* * OPEN * ------------------------------------------------------------------------- */STATIC streamscall intsdlm_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp){ psw_t flags; int mindex = 0; major_t cmajor = getmajor(*devp); minor_t cminor = getminor(*devp); struct dl *dl, **dpp; MOD_INC_USE_COUNT; if (q->q_ptr != NULL) { MOD_DEC_USE_COUNT; return (0); /* already open */ } if (sflag == MODOPEN || WR(q)->q_next) { ptrace(("%s: ERROR: cannot push as module\n", DRV_NAME)); MOD_DEC_USE_COUNT; return (EIO); } if (cmajor != CMAJOR_0 || cminor > 0) { MOD_DEC_USE_COUNT; return (ENXIO); } /* allocate a new device */ cminor = 1; spin_lock_irqsave(&master.lock, flags); for (dpp = &master.dl.list; *dpp; dpp = &(*dpp)->next) { major_t dmajor = (*dpp)->u.dev.cmajor; if (cmajor != dmajor) break; if (cmajor == dmajor) { minor_t dminor = (*dpp)->u.dev.cminor; if (cminor < dminor) break; if (cminor > dminor) continue; if (cminor == dminor) { if (++cminor >= NMINORS) { if (++mindex >= CMAJORS || !(cmajor = sdlm_majors[mindex])) break; cminor = 0; } continue; } } } if (mindex >= CMAJORS || !cmajor) { ptrace(("%s: ERROR: no device numbers available\n", DRV_NAME)); spin_unlock_irqrestore(&master.lock, flags); MOD_DEC_USE_COUNT; return (ENXIO); } printd(("%s: opened character device %d:%d\n", DRV_NAME, cmajor, cminor)); *devp = makedevice(cmajor, cminor); if (!(dl = sdlm_alloc_dl(q, dpp, cmajor, cminor, crp))) { ptrace(("%s: ERROR: no memory\n", DRV_NAME)); spin_unlock_irqrestore(&master.lock, flags); MOD_DEC_USE_COUNT; return (ENOMEM); } spin_unlock_irqrestore(&master.lock, flags); return (0);}/* * CLOSE * ------------------------------------------------------------------------- */STATIC streamscall intsdlm_close(queue_t *q, int flag, cred_t *crp){ struct dl *dl = DL_PRIV(q); psw_t flags; (void) dl; printd(("%s: %p: closing character device %hu:%hu\n", DRV_NAME, dl, dl->u.dev.cmajor, dl->u.dev.cminor)); spin_lock_irqsave(&master.lock, flags); { sdlm_free_dl(q); } spin_unlock_irqrestore(&master.lock, flags); MOD_DEC_USE_COUNT; return (0);}/* * ========================================================================= * * Registration and initialization * * ========================================================================= */#ifdef LINUX/* * Linux Registration * ------------------------------------------------------------------------- */unsigned short modid = DRV_ID;#ifndef module_paramMODULE_PARM(modid, "h");#elsemodule_param(modid, ushort, 0);#endifMODULE_PARM_DESC(modid, "Module ID for the SDL-MUX driver. (0 for allocation.)");major_t major = CMAJOR_0;#ifndef module_paramMODULE_PARM(major, "h");#elsemodule_param(major, uint, 0);#endifMODULE_PARM_DESC(major, "Device number for the SDL-MUX driver. (0 for allocation.)");/* * Linux Fast-STREAMS Registration * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */#ifdef LFSSTATIC struct cdevsw sdlm_cdev = { .d_name = DRV_NAME, .d_str = &sdlminfo, .d_flag = 0, .d_fop = NULL, .d_mode = S_IFCHR, .d_kmod = THIS_MODULE,};STATIC intsdlm_register_strdev(major_t major){ int err; if ((err = register_strdev(&sdlm_cdev, major)) < 0) return (err); return (0);}STATIC intsdlm_unregister_strdev(major_t major){ int err; if ((err = unregister_strdev(&sdlm_cdev, major)) < 0) return (err); return (0);}#endif /* LFS *//* * Linux STREAMS Registration * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */#ifdef LISSTATIC intsdlm_register_strdev(major_t major){ int err; if ((err = lis_register_strdev(major, &sdlminfo, UNITS, DRV_NAME)) < 0) return (err); return (0);}STATIC intsdlm_unregister_strdev(major_t major){ int err; if ((err = lis_unregister_strdev(major)) < 0) return (err); return (0);}#endif /* LIS */MODULE_STATIC void __exitsdlmterminate(void){ int err, mindex; for (mindex = CMAJORS - 1; mindex >= 0; mindex--) { if (sdlm_majors[mindex]) { if ((err = sdlm_unregister_strdev(sdlm_majors[mindex]))) cmn_err(CE_PANIC, "%s: cannot unregister major %d", DRV_NAME, sdlm_majors[mindex]); if (mindex) sdlm_majors[mindex] = 0; } } if ((err = sdlm_term_caches())) cmn_err(CE_WARN, "%s: could not terminate caches", DRV_NAME); return;}MODULE_STATIC int __initsdlminit(void){ int err, mindex = 0; cmn_err(CE_NOTE, DRV_BANNER); /* console splash */ if ((err = sdlm_init_caches())) { cmn_err(CE_WARN, "%s: could not init caches, err = %d", DRV_NAME, err); sdlmterminate(); return (err); } for (mindex = 0; mindex < CMAJORS; mindex++) { if ((err = sdlm_register_strdev(sdlm_majors[mindex])) < 0) { if (mindex) { cmn_err(CE_WARN, "%s: could not register major %d", DRV_NAME, sdlm_majors[mindex]); continue; } else { cmn_err(CE_WARN, "%s: could not register driver, err = %d", DRV_NAME, err); sdlmterminate(); return (err); } } if (sdlm_majors[mindex] == 0) sdlm_majors[mindex] = err;#if 0 LIS_DEVFLAGS(sdlm_majors[mindex]) |= LIS_MODFLG_CLONE;#endif if (major == 0) major = sdlm_majors[0]; } return (0);}/* * Linux Kernel Module Initialization * ------------------------------------------------------------------------- */module_init(sdlminit);module_exit(sdlmterminate);#endif /* LINUX */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -