/*---------------------------------------------------------------------------* * variable unit algorithm B channel idle check timeout function *---------------------------------------------------------------------------*/ static void i4b_idle_check_var_unit(call_desc_t *cd) { switch(cd->idletime_state) { /* see if there has been any activity within the last idle_time seconds */ case IST_CHECK: if( i4b_get_idletime(cd) > (SECOND - cd->shorthold_data.idle_time)) { /* activity detected */ /* check again in one second */ callout_reset(&cd->idle_timeout, hz, (void *)i4b_idle_check, cd); cd->timeout_active = 1; cd->idletime_state = IST_CHECK; NDBGL4(L4_TIMO, "%ld: outgoing-call, var idle timeout - activity at %ld, continuing", (long)SECOND, (long)i4b_get_idletime(cd)); } else { /* no activity, hangup */ NDBGL4(L4_TIMO, "%ld: outgoing-call, var idle timeout - last activity at %ld", (long)SECOND, (long)i4b_get_idletime(cd)); (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL); i4b_l4_idle_timeout_ind(cd); cd->idletime_state = IST_IDLE; } break; default: NDBGL4(L4_ERR, "outgoing-call: var idle timeout invalid idletime_state value!"); cd->idletime_state = IST_IDLE; break; } }
static uint32_t iavc_tx_capimsg(iavc_softc_t *sc, struct mbuf *m) { uint32_t txlen = 0; u_int8_t *dmabuf; if (sc->sc_dma) { /* Copy message to DMA buffer. */ if (m->m_next) dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_DATA_B3_REQ); else dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_MESSAGE); dmabuf = amcc_put_word(dmabuf, m->m_len); memcpy(dmabuf, m->m_data, m->m_len); dmabuf += m->m_len; txlen = 5 + m->m_len; if (m->m_next) { dmabuf = amcc_put_word(dmabuf, m->m_next->m_len); memcpy(dmabuf, m->m_next->m_data, m->m_next->m_len); txlen += 4 + m->m_next->m_len; } } else { /* Use PIO. */ if (m->m_next) { iavc_put_byte(sc, SEND_DATA_B3_REQ); NDBGL4(L4_IAVCDBG, "iavc%d: tx SDB3R msg, len = %d", sc->sc_unit, m->m_len); } else { iavc_put_byte(sc, SEND_MESSAGE); NDBGL4(L4_IAVCDBG, "iavc%d: tx SM msg, len = %d", sc->sc_unit, m->m_len); } #if 0 { u_int8_t *p = mtod(m, u_int8_t*); int len; for (len = 0; len < m->m_len; len++) { printf(" %02x", *p++); if (len && (len % 16) == 0) printf("\n"); } if (len % 16) printf("\n"); } #endif iavc_put_slice(sc, m->m_data, m->m_len); if (m->m_next) iavc_put_slice(sc, m->m_next->m_data, m->m_next->m_len); } return txlen; }
/*---------------------------------------------------------------------------* * i4bputqueue_hipri - put message into front of queue to userland *---------------------------------------------------------------------------*/ void i4bputqueue_hipri(struct mbuf *m) { if(!openflag) { i4b_Dfreembuf(m); return; } crit_enter(); if(IF_QFULL(&i4b_rdqueue)) { struct mbuf *m1; IF_DEQUEUE(&i4b_rdqueue, m1); i4b_Dfreembuf(m1); NDBGL4(L4_ERR, "ERROR, queue full, removing entry!"); } IF_PREPEND(&i4b_rdqueue, m); crit_exit(); if(readflag) { readflag = 0; wakeup((caddr_t) &i4b_rdqueue); } KNOTE(&kq_rd_info.ki_note, 0); }
/*---------------------------------------------------------------------------* * send MSG_DISCONNECT_IND message to userland *---------------------------------------------------------------------------*/ void i4b_l4_disconnect_ind(call_desc_t *cd) { struct mbuf *m; if(cd->timeout_active) callout_stop(&cd->idle_timeout); if(cd->dlt != NULL) { (*cd->dlt->line_disconnected)(cd->driver_unit, (void *)cd); i4b_unlink_bchandrvr(cd); } if((cd->channelid >= 0) && (cd->channelid < ctrl_desc[cd->controller].nbch)) { ctrl_desc[cd->controller].bch_state[cd->channelid] = BCH_ST_FREE; } else { /* no error, might be hunting call for callback */ NDBGL4(L4_MSG, "channel free not valid but %d!", cd->channelid); } if((m = i4b_Dgetmbuf(sizeof(msg_disconnect_ind_t))) != NULL) { msg_disconnect_ind_t *mp = (msg_disconnect_ind_t *)m->m_data; mp->header.type = MSG_DISCONNECT_IND; mp->header.cdid = cd->cdid; mp->cause = cd->cause_in; i4bputqueue(m); } }
/*---------------------------------------------------------------------------* * send MSG_CONNECT_ACTIVE_IND message to userland *---------------------------------------------------------------------------*/ void i4b_l4_connect_active_ind(call_desc_t *cd) { struct mbuf *m; crit_enter(); cd->last_active_time = cd->connect_time = SECOND; NDBGL4(L4_TIMO, "last_active/connect_time=%ld", (long)cd->connect_time); i4b_link_bchandrvr(cd); (*cd->dlt->line_connected)(cd->driver_unit, (void *)cd); i4b_l4_setup_timeout(cd); crit_exit(); if((m = i4b_Dgetmbuf(sizeof(msg_connect_active_ind_t))) != NULL) { msg_connect_active_ind_t *mp = (msg_connect_active_ind_t *)m->m_data; mp->header.type = MSG_CONNECT_ACTIVE_IND; mp->header.cdid = cd->cdid; mp->controller = cd->controller; mp->channel = cd->channelid; if(cd->datetime[0] != '\0') strcpy(mp->datetime, cd->datetime); else mp->datetime[0] = '\0'; i4bputqueue(m); } }
/*---------------------------------------------------------------------------* * this routine is called from L4 handler at connect time *---------------------------------------------------------------------------*/ static void rbch_connect(void *softc, void *cdp) { call_desc_t *cd = (call_desc_t *)cdp; struct rbch_softc *sc = softc; sc->sc_bprot = cd->bprot; #if I4BRBCHACCT if(sc->sc_bprot == BPROT_RHDLC) { sc->sc_iinb = 0; sc->sc_ioutb = 0; sc->sc_linb = 0; sc->sc_loutb = 0; START_TIMER(sc->sc_callout, rbch_timeout, sc, I4BRBCHACCTINTVL*hz); } #endif if(!(sc->sc_devstate & ST_CONNECTED)) { NDBGL4(L4_RBCHDBG, "B channel %d at ISDN %d, wakeup", cd->channelid, cd->isdnif); sc->sc_devstate |= ST_CONNECTED; sc->sc_cd = cdp; wakeup((void *)sc); selnotify(&sc->selp, 0, 0); } }
/*---------------------------------------------------------------------------* * this routine is called from the HSCX interrupt handler * when the last frame has been sent out and there is no * further frame (mbuf) in the tx queue. *---------------------------------------------------------------------------*/ static void rbch_tx_queue_empty(void *softc) { struct rbch_softc *sc = softc; if(sc->sc_devstate & ST_WRWAITEMPTY) { NDBGL4(L4_RBCHDBG, "(minor=%d): wakeup", sc->sc_unit); sc->sc_devstate &= ~ST_WRWAITEMPTY; wakeup((void *) &sc->sc_ilt->tx_queue); } else { NDBGL4(L4_RBCHDBG, "(minor=%d) NO wakeup", sc->sc_unit); } selnotify(&sc->selp, 0, 0); }
/*---------------------------------------------------------------------------* * fixed unit algorithm B channel idle check timeout setup *---------------------------------------------------------------------------*/ static void i4b_l4_setup_timeout_fix_unit(call_desc_t *cd) { /* outgoing call */ if((cd->shorthold_data.idle_time > 0) && (cd->shorthold_data.unitlen_time == 0)) { /* outgoing call: simple max idletime check */ callout_reset(&cd->idle_timeout, hz / 2, (void *)i4b_idle_check, cd); cd->timeout_active = 1; NDBGL4(L4_TIMO, "%ld: outgoing-call, setup idle_time to %ld", (long)SECOND, (long)cd->shorthold_data.idle_time); } else if((cd->shorthold_data.unitlen_time > 0) && (cd->shorthold_data.unitlen_time > (cd->shorthold_data.idle_time + cd->shorthold_data.earlyhup_time))) { /* outgoing call: full shorthold mode check */ callout_reset(&cd->idle_timeout, hz * (cd->shorthold_data.unitlen_time - (cd->shorthold_data.idle_time + cd->shorthold_data.earlyhup_time)), (void *)i4b_idle_check, cd); cd->timeout_active = 1; cd->idletime_state = IST_NONCHK; NDBGL4(L4_TIMO, "%ld: outgoing-call, start %ld sec nocheck window", (long)SECOND, (long)(cd->shorthold_data.unitlen_time - (cd->shorthold_data.idle_time + cd->shorthold_data.earlyhup_time))); if(cd->aocd_flag == 0) { cd->units_type = CHARGE_CALC; cd->cunits++; i4b_l4_charging_ind(cd); } } else { /* parms somehow got wrong .. */ NDBGL4(L4_ERR, "%ld: ERROR: idletime[%ld]+earlyhup[%ld] > unitlength[%ld]!", (long)SECOND, (long)cd->shorthold_data.idle_time, (long)cd->shorthold_data.earlyhup_time, (long)cd->shorthold_data.unitlen_time); } }
static void iavc_handle_rx(iavc_softc_t *sc) { u_int8_t *dmabuf = 0, cmd; if (sc->sc_dma) { dmabuf = amcc_get_byte(&sc->sc_recvbuf[0], &cmd); } else { cmd = iavc_get_byte(sc); } NDBGL4(L4_IAVCDBG, "iavc%d: command = 0x%02x", sc->sc_unit, cmd); switch (cmd) { case RECEIVE_DATA_B3_IND: iavc_receive(sc, dmabuf, 1); break; case RECEIVE_MESSAGE: iavc_receive(sc, dmabuf, 0); break; case RECEIVE_NEW_NCCI: iavc_receive_new_ncci(sc, dmabuf); break; case RECEIVE_FREE_NCCI: iavc_receive_free_ncci(sc, dmabuf); break; case RECEIVE_START: iavc_receive_start(sc); break; case RECEIVE_STOP: iavc_receive_stop(sc); break; case RECEIVE_INIT: iavc_receive_init(sc, dmabuf); break; case RECEIVE_TASK_READY: iavc_receive_task_ready(sc, dmabuf); break; case RECEIVE_DEBUGMSG: iavc_receive_debugmsg(sc, dmabuf); break; default: aprint_error_dev(&sc->sc_dev, "unknown msg %02x\n", cmd); } }
/*---------------------------------------------------------------------------* * this routine is called from L4 handler at disconnect time *---------------------------------------------------------------------------*/ static void rbch_disconnect(void *softc, void *cdp) { call_desc_t *cd = cdp; struct rbch_softc *sc = softc; int s; if(cd != sc->sc_cd) { NDBGL4(L4_RBCHDBG, "B channel %d at ISDN %d not active", cd->channelid, cd->isdnif); return; } s = splnet(); NDBGL4(L4_RBCHDBG, "B channel %d at ISDN %d disconnect", cd->channelid, cd->isdnif); sc->sc_devstate &= ~ST_CONNECTED; #if I4BRBCHACCT if (sc->sc_cd) i4b_l4_accounting(sc->sc_cd->cdid, ACCT_FINAL, sc->sc_ioutb, sc->sc_iinb, 0, 0, sc->sc_ioutb, sc->sc_iinb); STOP_TIMER(sc->sc_callout, rbch_timeout, sc); #endif sc->sc_cd = NULL; if (sc->sc_devstate & ST_RDWAITDATA) wakeup(&sc->sc_ilt->rx_queue); if (sc->sc_devstate & ST_WRWAITEMPTY) wakeup(&sc->sc_ilt->tx_queue); splx(s); selnotify(&sc->selp, 0, 0); }
/*---------------------------------------------------------------------------* * device driver select *---------------------------------------------------------------------------*/ PDEVSTATIC int isdnbchanselect(dev_t dev, int rw, struct lwp *l) { int unit = minor(dev); struct rbch_softc *sc = &rbch_softc[unit]; int s; s = splhigh(); if(!(sc->sc_devstate & ST_ISOPEN)) { splx(s); NDBGL4(L4_RBCHDBG, "(minor=%d) not open anymore", unit); return(1); } if(sc->sc_devstate & ST_CONNECTED) { struct ifqueue *iqp; switch(rw) { case FREAD: if(sc->sc_bprot == BPROT_RHDLC) iqp = &sc->sc_hdlcq; else iqp = isdn_linktab[unit]->rx_queue; if(!IF_QEMPTY(iqp)) { splx(s); return(1); } break; case FWRITE: if(!IF_QFULL(isdn_linktab[unit]->rx_queue)) { splx(s); return(1); } break; default: splx(s); return 0; } } selrecord(l, &sc->selp); splx(s); return(0); }
/*---------------------------------------------------------------------------* * this routine is called from the HSCX interrupt handler * when a new frame (mbuf) has been received and is to be put on * the rx queue. *---------------------------------------------------------------------------*/ static void rbch_rx_data_rdy(void *softc) { struct rbch_softc *sc = softc; if(sc->sc_bprot == BPROT_RHDLC) { register struct mbuf *m; if((m = *sc->sc_ilt->rx_mbuf) == NULL) return; m->m_pkthdr.len = m->m_len; if(IF_QFULL(&sc->sc_hdlcq)) { NDBGL4(L4_RBCHDBG, "(minor=%d) hdlc rx queue full!", sc->sc_unit); m_freem(m); } else { IF_ENQUEUE(&sc->sc_hdlcq, m); } } if(sc->sc_devstate & ST_RDWAITDATA) { NDBGL4(L4_RBCHDBG, "(minor=%d) wakeup", sc->sc_unit); sc->sc_devstate &= ~ST_RDWAITDATA; wakeup((void *) &sc->sc_ilt->rx_queue); } else { NDBGL4(L4_RBCHDBG, "(minor=%d) NO wakeup", sc->sc_unit); } selnotify(&sc->selp, 0, 0); }
/*---------------------------------------------------------------------------* * B channel idle check timeout setup *---------------------------------------------------------------------------*/ static void i4b_l4_setup_timeout(call_desc_t *cd) { NDBGL4(L4_TIMO, "%ld: direction %d, shorthold algorithm %d", (long)SECOND, cd->dir, cd->shorthold_data.shorthold_algorithm); cd->timeout_active = 0; cd->idletime_state = IST_IDLE; if((cd->dir == DIR_INCOMING) && (cd->max_idle_time > 0)) { /* incoming call: simple max idletime check */ callout_reset(&cd->idle_timeout, hz / 2, (void *)i4b_idle_check, cd); cd->timeout_active = 1; NDBGL4(L4_TIMO, "%ld: incoming-call, setup max_idle_time to %ld", (long)SECOND, (long)cd->max_idle_time); } else if((cd->dir == DIR_OUTGOING) && (cd->shorthold_data.idle_time > 0)) { switch( cd->shorthold_data.shorthold_algorithm ) { default: /* fall into the old fix algorithm */ case SHA_FIXU: i4b_l4_setup_timeout_fix_unit( cd ); break; case SHA_VARU: i4b_l4_setup_timeout_var_unit( cd ); break; } } else { NDBGL4(L4_TIMO, "no idle_timeout configured"); } }
/*---------------------------------------------------------------------------* * close rbch device *---------------------------------------------------------------------------*/ PDEVSTATIC int isdnbchanclose(dev_t dev, int flag, int fmt, struct lwp *l) { int unit = minor(dev); struct rbch_softc *sc = &rbch_softc[unit]; if(sc->sc_devstate & ST_CONNECTED) i4b_l4_drvrdisc(sc->sc_cd->cdid); sc->sc_devstate &= ~ST_ISOPEN; rbch_clrq(sc); NDBGL4(L4_RBCHDBG, "channel %d, closed", unit); return(0); }
/*---------------------------------------------------------------------------* * variable unit algorithm B channel idle check timeout setup *---------------------------------------------------------------------------*/ static void i4b_l4_setup_timeout_var_unit(call_desc_t *cd) { /* outgoing call: variable unit idletime check */ /* * start checking for an idle connect one second before the end of the unit. * The one second takes into account of rounding due to the driver only * using the seconds and not the uSeconds of the current time */ cd->idletime_state = IST_CHECK; /* move directly to the checking state */ callout_reset(&cd->idle_timeout, hz * (cd->shorthold_data.unitlen_time - 1), (void *)i4b_idle_check, cd); cd->timeout_active = 1; NDBGL4(L4_TIMO, "%ld: outgoing-call, var idle time - setup to %ld", (long)SECOND, (long)cd->shorthold_data.unitlen_time); }
/*---------------------------------------------------------------------------* * open rbch device *---------------------------------------------------------------------------*/ PDEVSTATIC int isdnbchanopen(dev_t dev, int flag, int fmt, struct lwp *l) { int unit = minor(dev); if(unit >= NISDNBCHAN) return(ENXIO); if(rbch_softc[unit].sc_devstate & ST_ISOPEN) return(EBUSY); #if 0 rbch_clrq(unit); #endif rbch_softc[unit].sc_devstate |= ST_ISOPEN; NDBGL4(L4_RBCHDBG, "unit %d, open", unit); return(0); }
static int iavc_receive_start(iavc_softc_t *sc, u_int8_t *dmabuf) { struct mbuf *m = i4b_Dgetmbuf(3); u_int8_t *p; if (sc->sc_blocked && sc->sc_state == IAVC_UP) printf("iavc%d: receive_start\n", sc->sc_unit); if (!m) { printf("iavc%d: can't get memory\n", sc->sc_unit); return (ENOMEM); } /* * byte 0x73 = SEND_POLLACK */ p = amcc_put_byte(mtod(m, u_int8_t*), 0); p = amcc_put_byte(p, 0); p = amcc_put_byte(p, SEND_POLLACK); _IF_PREPEND(&sc->sc_txq, m); NDBGL4(L4_IAVCDBG, "iavc%d: blocked = %d, state = %d", sc->sc_unit, sc->sc_blocked, sc->sc_state); sc->sc_blocked = FALSE; iavc_start_tx(sc); /* If this was our first START, register our readiness */ if (sc->sc_state != IAVC_UP) { sc->sc_state = IAVC_UP; capi_ll_control(&sc->sc_capi, CAPI_CTRL_READY, TRUE); } return 0; }
/*---------------------------------------------------------------------------* * i4bputqueue_hipri - put message into front of queue to userland *---------------------------------------------------------------------------*/ void i4bputqueue_hipri(struct mbuf *m) { int x; if(!openflag) { i4b_Dfreembuf(m); return; } x = splnet(); if(IF_QFULL(&i4b_rdqueue)) { struct mbuf *m1; IF_DEQUEUE(&i4b_rdqueue, m1); i4b_Dfreembuf(m1); NDBGL4(L4_ERR, "ERROR, queue full, removing entry!"); } IF_PREPEND(&i4b_rdqueue, m); splx(x); if(readflag) { readflag = 0; wakeup((caddr_t) &i4b_rdqueue); } if(selflag) { selflag = 0; selwakeup(&select_rd_info); } }
/*---------------------------------------------------------------------------* * i4bputqueue - put message into queue to userland *---------------------------------------------------------------------------*/ void i4bputqueue(struct mbuf *m) { int x; if(!openflag) { i4b_Dfreembuf(m); return; } x = splnet(); if(IF_QFULL(&i4b_rdqueue)) { struct mbuf *m1; IF_DEQUEUE(&i4b_rdqueue, m1); i4b_Dfreembuf(m1); NDBGL4(L4_ERR, "ERROR, queue full, removing entry!"); } IF_ENQUEUE(&i4b_rdqueue, m); splx(x); if(readflag) { readflag = 0; wakeup((void *) &i4b_rdqueue); } if(selflag) { selflag = 0; selnotify(&select_rd_info, 0, 0); } }
static int iavc_receive_start(iavc_softc_t *sc) { struct mbuf *m = i4b_Dgetmbuf(3); u_int8_t *p; if (sc->sc_blocked && sc->sc_state == IAVC_UP) printf("%s: receive_start\n", device_xname(&sc->sc_dev)); if (!m) { aprint_error_dev(&sc->sc_dev, "can't get memory\n"); return (ENOMEM); } /* * byte 0x73 = SEND_POLLACK */ p = amcc_put_byte(mtod(m, u_int8_t*), 0); p = amcc_put_byte(p, 0); p = amcc_put_byte(p, SEND_POLLACK); IF_PREPEND(&sc->sc_txq, m); NDBGL4(L4_IAVCDBG, "%s: blocked = %d, state = %d", device_xname(&sc->sc_dev), sc->sc_blocked, sc->sc_state); sc->sc_blocked = 0; iavc_start_tx(sc); /* If this was our first START, register our readiness */ if (sc->sc_state != IAVC_UP) { sc->sc_state = IAVC_UP; capi_ll_control(&sc->sc_capi, CAPI_CTRL_READY, 1); } return 0; }
/*---------------------------------------------------------------------------* * fixed unit algorithm B channel idle check timeout function *---------------------------------------------------------------------------*/ static void i4b_idle_check_fix_unit(call_desc_t *cd) { /* simple idletime calculation */ if((cd->shorthold_data.idle_time > 0) && (cd->shorthold_data.unitlen_time == 0)) { if((i4b_get_idletime(cd) + cd->shorthold_data.idle_time) <= SECOND) { NDBGL4(L4_TIMO, "%ld: outgoing-call-st, idle timeout, disconnecting!", (long)SECOND); (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL); i4b_l4_idle_timeout_ind(cd); } else { NDBGL4(L4_TIMO, "%ld: outgoing-call-st, activity, last_active=%ld, max_idle=%ld", (long)SECOND, (long)i4b_get_idletime(cd), (long)cd->shorthold_data.idle_time); callout_reset(&cd->idle_timeout, hz / 2, (void *)i4b_idle_check, cd); cd->timeout_active = 1; } } /* full shorthold mode calculation */ else if((cd->shorthold_data.unitlen_time > 0) && (cd->shorthold_data.unitlen_time > (cd->shorthold_data.idle_time + cd->shorthold_data.earlyhup_time))) { switch(cd->idletime_state) { case IST_NONCHK: /* end of non-check time */ callout_reset(&cd->idle_timeout, hz*(cd->shorthold_data.idle_time), (void *)i4b_idle_check, cd); cd->idletimechk_start = SECOND; cd->idletime_state = IST_CHECK; cd->timeout_active = 1; NDBGL4(L4_TIMO, "%ld: outgoing-call, idletime check window reached!", (long)SECOND); break; case IST_CHECK: /* end of idletime chk */ if((i4b_get_idletime(cd) > cd->idletimechk_start) && (i4b_get_idletime(cd) <= SECOND)) { /* activity detected */ callout_reset(&cd->idle_timeout, hz*(cd->shorthold_data.earlyhup_time), (void *)i4b_idle_check, cd); cd->timeout_active = 1; cd->idletime_state = IST_SAFE; NDBGL4(L4_TIMO, "%ld: outgoing-call, activity at %ld, wait earlyhup-end", (long)SECOND, (long)i4b_get_idletime(cd)); } else { /* no activity, hangup */ NDBGL4(L4_TIMO, "%ld: outgoing-call, idle timeout, last activity at %ld", (long)SECOND, (long)i4b_get_idletime(cd)); (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL); i4b_l4_idle_timeout_ind(cd); cd->idletime_state = IST_IDLE; } break; case IST_SAFE: /* end of earlyhup time */ callout_reset(&cd->idle_timeout, hz*(cd->shorthold_data.unitlen_time - (cd->shorthold_data.idle_time + cd->shorthold_data.earlyhup_time)), (void *)i4b_idle_check, cd); cd->timeout_active = 1; cd->idletime_state = IST_NONCHK; if(cd->aocd_flag == 0) { cd->units_type = CHARGE_CALC; cd->cunits++; i4b_l4_charging_ind(cd); } NDBGL4(L4_TIMO, "%ld: outgoing-call, earlyhup end, wait for idletime start", (long)SECOND); break; default: NDBGL4(L4_ERR, "outgoing-call: invalid idletime_state value!"); cd->idletime_state = IST_IDLE; break; } } }
/*---------------------------------------------------------------------------* * i4bioctl - device driver ioctl routine *---------------------------------------------------------------------------*/ PDEVSTATIC int isdnioctl(dev_t dev, u_long cmd, caddr_t data, int flag, struct proc *p) { struct isdn_l3_driver *d; call_desc_t *cd; int error = 0; if(minor(dev)) return(ENODEV); switch(cmd) { /* cdid request, reserve cd and return cdid */ case I4B_CDID_REQ: { msg_cdid_req_t *mir; mir = (msg_cdid_req_t *)data; cd = reserve_cd(); mir->cdid = cd->cdid; break; } /* connect request, dial out to remote */ case I4B_CONNECT_REQ: { msg_connect_req_t *mcr; mcr = (msg_connect_req_t *)data; /* setup ptr */ if((cd = cd_by_cdid(mcr->cdid)) == NULL)/* get cd */ { NDBGL4(L4_ERR, "I4B_CONNECT_REQ ioctl, cdid not found!"); error = EINVAL; break; } cd->bri = -1; cd->l3drv = NULL; d = isdn_find_l3_by_bri(mcr->controller); if (d == NULL) { error = EINVAL; break; } /* prevent dialling on leased lines */ if(d->protocol == PROTOCOL_D64S) { SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B); SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_LLDIAL); i4b_l4_disconnect_ind(cd); freecd_by_cd(cd); break; } cd->bri = mcr->controller; /* fill cd */ cd->l3drv = d; cd->bprot = mcr->bprot; cd->bchan_driver_index = mcr->driver; cd->bchan_driver_unit = mcr->driver_unit; cd->cr = get_rand_cr(cd->bri); cd->shorthold_data.shorthold_algorithm = mcr->shorthold_data.shorthold_algorithm; cd->shorthold_data.unitlen_time = mcr->shorthold_data.unitlen_time; cd->shorthold_data.idle_time = mcr->shorthold_data.idle_time; cd->shorthold_data.earlyhup_time = mcr->shorthold_data.earlyhup_time; cd->last_aocd_time = 0; if(mcr->unitlen_method == ULEN_METHOD_DYNAMIC) cd->aocd_flag = 1; else cd->aocd_flag = 0; cd->cunits = 0; cd->max_idle_time = 0; /* this is outgoing */ cd->dir = DIR_OUTGOING; NDBGL4(L4_TIMO, "I4B_CONNECT_REQ times, algorithm=%ld unitlen=%ld idle=%ld earlyhup=%ld", (long)cd->shorthold_data.shorthold_algorithm, (long)cd->shorthold_data.unitlen_time, (long)cd->shorthold_data.idle_time, (long)cd->shorthold_data.earlyhup_time); strcpy(cd->dst_telno, mcr->dst_telno); strcpy(cd->src_telno, mcr->src_telno); cd->display[0] = '\0'; SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B); SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NORMAL); switch(mcr->channel) { case CHAN_B1: case CHAN_B2: if(d->bch_state[mcr->channel] != BCH_ST_FREE) SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN); break; case CHAN_ANY: if((d->bch_state[CHAN_B1] != BCH_ST_FREE) && (d->bch_state[CHAN_B2] != BCH_ST_FREE)) SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN); break; default: SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN); break; } cd->channelid = mcr->channel; cd->isdntxdelay = mcr->txdelay; if((GET_CAUSE_VAL(cd->cause_in)) != CAUSE_I4B_NORMAL) { i4b_l4_disconnect_ind(cd); freecd_by_cd(cd); } else { d->l3driver->N_CONNECT_REQUEST(cd); } break; } /* connect response, accept/reject/ignore incoming call */ case I4B_CONNECT_RESP: { msg_connect_resp_t *mcrsp; mcrsp = (msg_connect_resp_t *)data; if((cd = cd_by_cdid(mcrsp->cdid)) == NULL)/* get cd */ { NDBGL4(L4_ERR, "I4B_CONNECT_RESP ioctl, cdid not found!"); error = EINVAL; break; } T400_stop(cd); cd->bchan_driver_index = mcrsp->driver; cd->bchan_driver_unit = mcrsp->driver_unit; cd->max_idle_time = mcrsp->max_idle_time; cd->shorthold_data.shorthold_algorithm = SHA_FIXU; cd->shorthold_data.unitlen_time = 0; /* this is incoming */ cd->shorthold_data.idle_time = 0; cd->shorthold_data.earlyhup_time = 0; cd->isdntxdelay = mcrsp->txdelay; NDBGL4(L4_TIMO, "I4B_CONNECT_RESP max_idle_time set to %ld seconds", (long)cd->max_idle_time); d = isdn_find_l3_by_bri(cd->bri); if (d == NULL) { error = EINVAL; break; } d->l3driver->N_CONNECT_RESPONSE(cd, mcrsp->response, mcrsp->cause); break; } /* disconnect request, actively terminate connection */ case I4B_DISCONNECT_REQ: { msg_discon_req_t *mdr; mdr = (msg_discon_req_t *)data; if((cd = cd_by_cdid(mdr->cdid)) == NULL)/* get cd */ { NDBGL4(L4_ERR, "I4B_DISCONNECT_REQ ioctl, cdid %d not found!", mdr->cdid); error = EINVAL; break; } /* preset causes with our cause */ cd->cause_in = cd->cause_out = mdr->cause; d = isdn_find_l3_by_bri(cd->bri); if (d == NULL) { error = EINVAL; break; } d->l3driver->N_DISCONNECT_REQUEST(cd, mdr->cause); break; } /* controller info request */ case I4B_CTRL_INFO_REQ: { msg_ctrl_info_req_t *mcir; struct isdn_l3_driver *d; int bri; mcir = (msg_ctrl_info_req_t *)data; bri = mcir->controller; memset(mcir, 0, sizeof(msg_ctrl_info_req_t)); mcir->controller = bri; mcir->ncontroller = isdn_count_bri(&mcir->maxbri); d = isdn_find_l3_by_bri(bri); if (d != NULL) { mcir->tei = d->tei; strncpy(mcir->devname, d->devname, sizeof(mcir->devname)-1); strncpy(mcir->cardname, d->card_name, sizeof(mcir->cardname)-1); } else { error = ENODEV; } break; } /* dial response */ case I4B_DIALOUT_RESP: { const struct isdn_l4_driver_functions *drv; msg_dialout_resp_t *mdrsp; void * l4_softc; mdrsp = (msg_dialout_resp_t *)data; drv = isdn_l4_get_driver(mdrsp->driver, mdrsp->driver_unit); if(drv != NULL) { l4_softc = (*drv->get_softc)(mdrsp->driver_unit); (*drv->dial_response)(l4_softc, mdrsp->stat, mdrsp->cause); } break; } /* update timeout value */ case I4B_TIMEOUT_UPD: { msg_timeout_upd_t *mtu; int x; mtu = (msg_timeout_upd_t *)data; NDBGL4(L4_TIMO, "I4B_TIMEOUT_UPD ioctl, alg %d, unit %d, idle %d, early %d!", mtu->shorthold_data.shorthold_algorithm, mtu->shorthold_data.unitlen_time, mtu->shorthold_data.idle_time, mtu->shorthold_data.earlyhup_time); if((cd = cd_by_cdid(mtu->cdid)) == NULL)/* get cd */ { NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, cdid not found!"); error = EINVAL; break; } switch( mtu->shorthold_data.shorthold_algorithm ) { case SHA_FIXU: /* * For this algorithm unitlen_time, * idle_time and earlyhup_time are used. */ if(!(mtu->shorthold_data.unitlen_time >= 0 && mtu->shorthold_data.idle_time >= 0 && mtu->shorthold_data.earlyhup_time >= 0)) { NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid args for fix unit algorithm!"); error = EINVAL; } break; case SHA_VARU: /* * For this algorithm unitlen_time and * idle_time are used. both must be * positive integers. earlyhup_time is * not used and must be 0. */ if(!(mtu->shorthold_data.unitlen_time > 0 && mtu->shorthold_data.idle_time >= 0 && mtu->shorthold_data.earlyhup_time == 0)) { NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid args for var unit algorithm!"); error = EINVAL; } break; default: NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid algorithm!"); error = EINVAL; break; } /* * any error set above requires us to break * out of the outer switch */ if(error != 0) break; x = splnet(); cd->shorthold_data.shorthold_algorithm = mtu->shorthold_data.shorthold_algorithm; cd->shorthold_data.unitlen_time = mtu->shorthold_data.unitlen_time; cd->shorthold_data.idle_time = mtu->shorthold_data.idle_time; cd->shorthold_data.earlyhup_time = mtu->shorthold_data.earlyhup_time; splx(x); break; } /* soft enable/disable interface */ case I4B_UPDOWN_IND: { msg_updown_ind_t *mui; const struct isdn_l4_driver_functions *drv; void * l4_softc; mui = (msg_updown_ind_t *)data; drv = isdn_l4_get_driver(mui->driver, mui->driver_unit); if (drv) { l4_softc = drv->get_softc(mui->driver_unit); (*drv->updown_ind)(l4_softc, mui->updown); } break; } /* send ALERT request */ case I4B_ALERT_REQ: { msg_alert_req_t *mar; mar = (msg_alert_req_t *)data; if((cd = cd_by_cdid(mar->cdid)) == NULL) { NDBGL4(L4_ERR, "I4B_ALERT_REQ ioctl, cdid not found!"); error = EINVAL; break; } T400_stop(cd); d = cd->l3drv; if (d == NULL) { error = EINVAL; break; } d->l3driver->N_ALERT_REQUEST(cd); break; } /* version/release number request */ case I4B_VR_REQ: { msg_vr_req_t *mvr; mvr = (msg_vr_req_t *)data; mvr->version = VERSION; mvr->release = REL; mvr->step = STEP; break; } /* set D-channel protocol for a controller */ case I4B_PROT_IND: { msg_prot_ind_t *mpi; mpi = (msg_prot_ind_t *)data; d = isdn_find_l3_by_bri(mpi->controller); if (d == NULL) { error = EINVAL; break; } d->protocol = mpi->protocol; break; } case I4B_L4DRIVER_LOOKUP: { msg_l4driver_lookup_t *lookup = (msg_l4driver_lookup_t*)data; lookup->name[L4DRIVER_NAME_SIZ-1] = 0; lookup->driver_id = isdn_l4_find_driverid(lookup->name); if (lookup->driver_id < 0) error = ENXIO; break; } /* Download request */ case I4B_CTRL_DOWNLOAD: { struct isdn_dr_prot *prots = NULL, *prots2 = NULL; struct isdn_download_request *r = (struct isdn_download_request*)data; int i; d = isdn_find_l3_by_bri(r->controller); if (d == NULL) { error = ENODEV; goto download_done; } if(d->l3driver->N_DOWNLOAD == NULL) { error = ENODEV; goto download_done; } prots = malloc(r->numprotos * sizeof(struct isdn_dr_prot), M_DEVBUF, M_WAITOK); prots2 = malloc(r->numprotos * sizeof(struct isdn_dr_prot), M_DEVBUF, M_WAITOK); if(!prots || !prots2) { error = ENOMEM; goto download_done; } copyin(r->protocols, prots, r->numprotos * sizeof(struct isdn_dr_prot)); for(i = 0; i < r->numprotos; i++) { prots2[i].microcode = malloc(prots[i].bytecount, M_DEVBUF, M_WAITOK); copyin(prots[i].microcode, prots2[i].microcode, prots[i].bytecount); prots2[i].bytecount = prots[i].bytecount; } error = d->l3driver->N_DOWNLOAD( d->l1_token, r->numprotos, prots2); download_done: if(prots2) { for(i = 0; i < r->numprotos; i++) { if(prots2[i].microcode) { free(prots2[i].microcode, M_DEVBUF); } } free(prots2, M_DEVBUF); } if(prots) { free(prots, M_DEVBUF); } break; } /* Diagnostic request */ case I4B_ACTIVE_DIAGNOSTIC: { struct isdn_diagnostic_request req, *r = (struct isdn_diagnostic_request*)data; req.in_param = req.out_param = NULL; d = isdn_find_l3_by_bri(r->controller); if (d == NULL) { error = ENODEV; goto diag_done; } if (d->l3driver->N_DIAGNOSTICS == NULL) { error = ENODEV; goto diag_done; } memcpy(&req, r, sizeof(req)); if(req.in_param_len) { /* XXX arbitrary limit */ if (req.in_param_len > I4B_ACTIVE_DIAGNOSTIC_MAXPARAMLEN) { error = EINVAL; goto diag_done; } req.in_param = malloc(r->in_param_len, M_DEVBUF, M_WAITOK); if(!req.in_param) { error = ENOMEM; goto diag_done; } error = copyin(r->in_param, req.in_param, req.in_param_len); if (error) goto diag_done; } if(req.out_param_len) { req.out_param = malloc(r->out_param_len, M_DEVBUF, M_WAITOK); if(!req.out_param) { error = ENOMEM; goto diag_done; } } error = d->l3driver->N_DIAGNOSTICS(d->l1_token, &req); if(!error && req.out_param_len) error = copyout(req.out_param, r->out_param, req.out_param_len); diag_done: if(req.in_param) free(req.in_param, M_DEVBUF); if(req.out_param) free(req.out_param, M_DEVBUF); break; } /* default */ default: error = ENOTTY; break; } return(error); }
static void iavc_start_tx(iavc_softc_t *sc) { struct mbuf *m; u_int8_t *dmabuf; u_int32_t txlen = 0; /* If device has put us on hold, punt. */ if (sc->sc_blocked) { return; } /* If using DMA and transmitter busy, punt. */ if (sc->sc_dma && (sc->sc_csr & EN_TX_TC_INT)) { return; } /* Else, see if we have messages to send. */ _IF_DEQUEUE(&sc->sc_txq, m); if (!m) { return; } /* Have message, will send. */ if (CAPIMSG_LEN(m->m_data)) { /* A proper CAPI message, possibly with B3 data */ if (sc->sc_dma) { /* Copy message to DMA buffer. */ if (m->m_next) { dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_DATA_B3_REQ); } else { dmabuf = amcc_put_byte(&sc->sc_sendbuf[0], SEND_MESSAGE); } dmabuf = amcc_put_word(dmabuf, m->m_len); bcopy(m->m_data, dmabuf, m->m_len); dmabuf += m->m_len; txlen = 5 + m->m_len; if (m->m_next) { dmabuf = amcc_put_word(dmabuf, m->m_next->m_len); bcopy(m->m_next->m_data, dmabuf, m->m_next->m_len); txlen += 4 + m->m_next->m_len; } } else { /* Use PIO. */ if (m->m_next) { iavc_put_byte(sc, SEND_DATA_B3_REQ); NDBGL4(L4_IAVCDBG, "iavc%d: tx SDB3R msg, len = %d", sc->sc_unit, m->m_len); } else { iavc_put_byte(sc, SEND_MESSAGE); NDBGL4(L4_IAVCDBG, "iavc%d: tx SM msg, len = %d", sc->sc_unit, m->m_len); } #if 0 { u_int8_t *p = mtod(m, u_int8_t*); int len; for (len = 0; len < m->m_len; len++) { printf(" %02x", *p++); if (len && (len % 16) == 0) printf("\n"); } if (len % 16) printf("\n"); } #endif iavc_put_slice(sc, m->m_data, m->m_len); if (m->m_next) { iavc_put_slice(sc, m->m_next->m_data, m->m_next->m_len); } } } else { /* A board control message to be sent as is */ if (sc->sc_dma) {
/*---------------------------------------------------------------------------* * B channel idle check timeout function *---------------------------------------------------------------------------*/ void i4b_idle_check(call_desc_t *cd) { if(cd->cdid == CDID_UNUSED) return; crit_enter(); /* failsafe */ if(cd->timeout_active == 0) { NDBGL4(L4_ERR, "ERROR: timeout_active == 0 !!!"); } else { cd->timeout_active = 0; } /* incoming connections, simple idletime check */ if(cd->dir == DIR_INCOMING) { if((i4b_get_idletime(cd) + cd->max_idle_time) <= SECOND) { NDBGL4(L4_TIMO, "%ld: incoming-call, line idle timeout, disconnecting!", (long)SECOND); (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(cd->cdid, (CAUSET_I4B << 8) | CAUSE_I4B_NORMAL); i4b_l4_idle_timeout_ind(cd); } else { NDBGL4(L4_TIMO, "%ld: incoming-call, activity, last_active=%ld, max_idle=%ld", (long)SECOND, (long)i4b_get_idletime(cd), (long)cd->max_idle_time); callout_reset(&cd->idle_timeout, hz / 2, (void *)i4b_idle_check, cd); cd->timeout_active = 1; } } /* outgoing connections */ else if(cd->dir == DIR_OUTGOING) { switch( cd->shorthold_data.shorthold_algorithm ) { case SHA_FIXU: i4b_idle_check_fix_unit( cd ); break; case SHA_VARU: i4b_idle_check_var_unit( cd ); break; default: NDBGL4(L4_TIMO, "%ld: bad value for shorthold_algorithm of %d", (long)SECOND, cd->shorthold_data.shorthold_algorithm); i4b_idle_check_fix_unit( cd ); break; } } crit_exit(); }
/*---------------------------------------------------------------------------* * rbch device ioctl handlibg *---------------------------------------------------------------------------*/ PDEVSTATIC int isdnbchanioctl(dev_t dev, IOCTL_CMD_T cmd, void *data, int flag, struct lwp *l) { int error = 0; int unit = minor(dev); struct rbch_softc *sc = &rbch_softc[unit]; switch(cmd) { case FIOASYNC: /* Set async mode */ if (*(int *)data) { NDBGL4(L4_RBCHDBG, "unit %d, setting async mode", unit); } else { NDBGL4(L4_RBCHDBG, "unit %d, clearing async mode", unit); } break; case FIONBIO: if (*(int *)data) { NDBGL4(L4_RBCHDBG, "unit %d, setting non-blocking mode", unit); sc->sc_devstate |= ST_NOBLOCK; } else { NDBGL4(L4_RBCHDBG, "unit %d, clearing non-blocking mode", unit); sc->sc_devstate &= ~ST_NOBLOCK; } break; case TIOCCDTR: /* Clear DTR */ if(sc->sc_devstate & ST_CONNECTED) { NDBGL4(L4_RBCHDBG, "unit %d, disconnecting for DTR down", unit); i4b_l4_drvrdisc(sc->sc_cd->cdid); } break; case I4B_RBCH_DIALOUT: { size_t x; for (x = 0; x < TELNO_MAX && ((char *)data)[x]; x++) ; if (x) { NDBGL4(L4_RBCHDBG, "%d, attempting dialout to %s", unit, (char *)data); i4b_l4_dialoutnumber(rbch_driver_id, unit, x, (char *)data); break; } /* fall through to SDTR */ } case TIOCSDTR: /* Set DTR */ NDBGL4(L4_RBCHDBG, "unit %d, attempting dialout (DTR)", unit); i4b_l4_dialout(rbch_driver_id, unit); break; case TIOCSETA: /* Set termios struct */ break; case TIOCGETA: /* Get termios struct */ *(struct termios *)data = sc->it_in; break; case TIOCMGET: *(int *)data = TIOCM_LE|TIOCM_DTR|TIOCM_RTS|TIOCM_CTS|TIOCM_DSR; if (sc->sc_devstate & ST_CONNECTED) *(int *)data |= TIOCM_CD; break; case I4B_RBCH_VR_REQ: { msg_vr_req_t *mvr; mvr = (msg_vr_req_t *)data; mvr->version = VERSION; mvr->release = REL; mvr->step = STEP; break; } default: /* Unknown stuff */ NDBGL4(L4_RBCHDBG, "(minor=%d) ioctl, unknown cmd %lx", unit, (u_long)cmd); error = EINVAL; break; } return(error); }
/*---------------------------------------------------------------------------* * write to rbch device *---------------------------------------------------------------------------*/ PDEVSTATIC int isdnbchanwrite(dev_t dev, struct uio * uio, int ioflag) { struct mbuf *m; int error = 0; int unit = minor(dev); struct rbch_softc *sc = &rbch_softc[unit]; int s; NDBGL4(L4_RBCHDBG, "unit %d, write", unit); s = splnet(); if(!(sc->sc_devstate & ST_ISOPEN)) { NDBGL4(L4_RBCHDBG, "unit %d, write while not open", unit); splx(s); return(EIO); } if((sc->sc_devstate & ST_NOBLOCK)) { if(!(sc->sc_devstate & ST_CONNECTED)) { splx(s); return(EWOULDBLOCK); } if(IF_QFULL(sc->sc_ilt->tx_queue) && (sc->sc_devstate & ST_ISOPEN)) { splx(s); return(EWOULDBLOCK); } } else { while(!(sc->sc_devstate & ST_CONNECTED)) { NDBGL4(L4_RBCHDBG, "unit %d, write wait init", unit); error = tsleep((void *) &rbch_softc[unit], TTIPRI | PCATCH, "wrrbch", 0 ); if(error == ERESTART) { splx(s); return (ERESTART); } else if(error == EINTR) { splx(s); NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait init", unit); return(EINTR); } else if(error) { splx(s); NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep init", unit, error); return(error); } tsleep((void *) &rbch_softc[unit], TTIPRI | PCATCH, "xrbch", (hz*1)); } while(IF_QFULL(sc->sc_ilt->tx_queue) && (sc->sc_devstate & ST_ISOPEN)) { sc->sc_devstate |= ST_WRWAITEMPTY; NDBGL4(L4_RBCHDBG, "unit %d, write queue full", unit); if ((error = tsleep((void *) &sc->sc_ilt->tx_queue, TTIPRI | PCATCH, "wrbch", 0)) != 0) { sc->sc_devstate &= ~ST_WRWAITEMPTY; if(error == ERESTART) { splx(s); return(ERESTART); } else if(error == EINTR) { splx(s); NDBGL4(L4_RBCHDBG, "unit %d, EINTR during wait write", unit); return(error); } else if(error) { splx(s); NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep write", unit, error); return(error); } else if (!(sc->sc_devstate & ST_CONNECTED)) { splx(s); return 0; } } } } if(!(sc->sc_devstate & ST_ISOPEN)) { NDBGL4(L4_RBCHDBG, "unit %d, not open anymore", unit); splx(s); return(EIO); } if((m = i4b_Bgetmbuf(BCH_MAX_DATALEN)) != NULL) { m->m_len = min(BCH_MAX_DATALEN, uio->uio_resid); NDBGL4(L4_RBCHDBG, "unit %d, write %d bytes", unit, m->m_len); error = uiomove(m->m_data, m->m_len, uio); if(IF_QFULL(sc->sc_ilt->tx_queue)) { m_freem(m); } else { IF_ENQUEUE(sc->sc_ilt->tx_queue, m); } (*sc->sc_ilt->bchannel_driver->bch_tx_start)(sc->sc_ilt->l1token, sc->sc_ilt->channel); } splx(s); return(error); }
/*---------------------------------------------------------------------------* * read from rbch device *---------------------------------------------------------------------------*/ PDEVSTATIC int isdnbchanread(dev_t dev, struct uio *uio, int ioflag) { struct mbuf *m; int error = 0; int unit = minor(dev); struct ifqueue *iqp; struct rbch_softc *sc = &rbch_softc[unit]; int s; NDBGL4(L4_RBCHDBG, "unit %d, enter read", unit); s = splnet(); if(!(sc->sc_devstate & ST_ISOPEN)) { splx(s); NDBGL4(L4_RBCHDBG, "unit %d, read while not open", unit); return(EIO); } if((sc->sc_devstate & ST_NOBLOCK)) { if(!(sc->sc_devstate & ST_CONNECTED)) { splx(s); return(EWOULDBLOCK); } if(sc->sc_bprot == BPROT_RHDLC) iqp = &sc->sc_hdlcq; else iqp = sc->sc_ilt->rx_queue; if(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN)) { splx(s); return(EWOULDBLOCK); } } else { while(!(sc->sc_devstate & ST_CONNECTED)) { NDBGL4(L4_RBCHDBG, "unit %d, wait read init", unit); if((error = tsleep((void *) &rbch_softc[unit], TTIPRI | PCATCH, "rrrbch", 0 )) != 0) { splx(s); NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep", unit, error); return(error); } } if(sc->sc_bprot == BPROT_RHDLC) iqp = &sc->sc_hdlcq; else iqp = sc->sc_ilt->rx_queue; while(IF_QEMPTY(iqp) && (sc->sc_devstate & ST_ISOPEN)) { sc->sc_devstate |= ST_RDWAITDATA; NDBGL4(L4_RBCHDBG, "unit %d, wait read data", unit); if((error = tsleep((void *) &sc->sc_ilt->rx_queue, TTIPRI | PCATCH, "rrbch", 0 )) != 0) { splx(s); NDBGL4(L4_RBCHDBG, "unit %d, error %d tsleep read", unit, error); sc->sc_devstate &= ~ST_RDWAITDATA; return(error); } else if (!(sc->sc_devstate & ST_CONNECTED)) { splx(s); return 0; } } } IF_DEQUEUE(iqp, m); NDBGL4(L4_RBCHDBG, "unit %d, read %d bytes", unit, m->m_len); if(m && m->m_len) { error = uiomove(m->m_data, m->m_len, uio); } else { NDBGL4(L4_RBCHDBG, "unit %d, error %d uiomove", unit, error); error = EIO; } if(m) i4b_Bfreembuf(m); splx(s); return(error); }
/*---------------------------------------------------------------------------* * i4bioctl - device driver ioctl routine *---------------------------------------------------------------------------*/ PDEVSTATIC int i4bioctl(struct dev_ioctl_args *ap) { cdev_t dev = ap->a_head.a_dev; caddr_t data = ap->a_data; call_desc_t *cd; int error = 0; if(minor(dev)) return(ENODEV); switch(ap->a_cmd) { /* cdid request, reserve cd and return cdid */ case I4B_CDID_REQ: { msg_cdid_req_t *mir; mir = (msg_cdid_req_t *)data; cd = reserve_cd(); mir->cdid = cd->cdid; break; } /* connect request, dial out to remote */ case I4B_CONNECT_REQ: { msg_connect_req_t *mcr; mcr = (msg_connect_req_t *)data; /* setup ptr */ if((cd = cd_by_cdid(mcr->cdid)) == NULL)/* get cd */ { NDBGL4(L4_ERR, "I4B_CONNECT_REQ ioctl, cdid not found!"); error = EINVAL; break; } /* prevent dialling on leased lines */ if(ctrl_desc[mcr->controller].protocol == PROTOCOL_D64S) { SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B); SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_LLDIAL); i4b_l4_disconnect_ind(cd); freecd_by_cd(cd); break; } cd->controller = mcr->controller; /* fill cd */ cd->bprot = mcr->bprot; cd->driver = mcr->driver; cd->driver_unit = mcr->driver_unit; cd->cr = get_rand_cr(ctrl_desc[cd->controller].unit); cd->shorthold_data.shorthold_algorithm = mcr->shorthold_data.shorthold_algorithm; cd->shorthold_data.unitlen_time = mcr->shorthold_data.unitlen_time; cd->shorthold_data.idle_time = mcr->shorthold_data.idle_time; cd->shorthold_data.earlyhup_time = mcr->shorthold_data.earlyhup_time; cd->last_aocd_time = 0; if(mcr->unitlen_method == ULEN_METHOD_DYNAMIC) cd->aocd_flag = 1; else cd->aocd_flag = 0; cd->cunits = 0; cd->max_idle_time = 0; /* this is outgoing */ cd->dir = DIR_OUTGOING; NDBGL4(L4_TIMO, "I4B_CONNECT_REQ times, algorithm=%ld unitlen=%ld idle=%ld earlyhup=%ld", (long)cd->shorthold_data.shorthold_algorithm, (long)cd->shorthold_data.unitlen_time, (long)cd->shorthold_data.idle_time, (long)cd->shorthold_data.earlyhup_time); strcpy(cd->dst_telno, mcr->dst_telno); strcpy(cd->src_telno, mcr->src_telno); if(mcr->keypad[0] != '\0') strcpy(cd->keypad, mcr->keypad); else cd->keypad[0] = '\0'; cd->display[0] = '\0'; SET_CAUSE_TYPE(cd->cause_in, CAUSET_I4B); SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NORMAL); switch(mcr->channel) { case CHAN_B1: case CHAN_B2: if(ctrl_desc[mcr->controller].bch_state[mcr->channel] != BCH_ST_FREE) SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN); break; case CHAN_ANY: { int i; for (i = 0; i < ctrl_desc[mcr->controller].nbch && ctrl_desc[mcr->controller].bch_state[i] != BCH_ST_FREE; i++); if (i == ctrl_desc[mcr->controller].nbch) SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN); /* else mcr->channel = i; XXX */ } break; default: SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN); break; } cd->channelid = mcr->channel; cd->isdntxdelay = mcr->txdelay; /* check whether we have a pointer. Seems like */ /* this should be adequate. GJ 19.09.97 */ if(ctrl_desc[cd->controller].N_CONNECT_REQUEST == NULL) /*XXX*/ SET_CAUSE_VAL(cd->cause_in, CAUSE_I4B_NOCHAN); if((GET_CAUSE_VAL(cd->cause_in)) != CAUSE_I4B_NORMAL) { i4b_l4_disconnect_ind(cd); freecd_by_cd(cd); } else { (*ctrl_desc[cd->controller].N_CONNECT_REQUEST)(mcr->cdid); } break; } /* connect response, accept/reject/ignore incoming call */ case I4B_CONNECT_RESP: { msg_connect_resp_t *mcrsp; mcrsp = (msg_connect_resp_t *)data; if((cd = cd_by_cdid(mcrsp->cdid)) == NULL)/* get cd */ { NDBGL4(L4_ERR, "I4B_CONNECT_RESP ioctl, cdid not found!"); error = EINVAL; break; } T400_stop(cd); cd->driver = mcrsp->driver; cd->driver_unit = mcrsp->driver_unit; cd->max_idle_time = mcrsp->max_idle_time; cd->shorthold_data.shorthold_algorithm = SHA_FIXU; cd->shorthold_data.unitlen_time = 0; /* this is incoming */ cd->shorthold_data.idle_time = 0; cd->shorthold_data.earlyhup_time = 0; cd->isdntxdelay = mcrsp->txdelay; NDBGL4(L4_TIMO, "I4B_CONNECT_RESP max_idle_time set to %ld seconds", (long)cd->max_idle_time); (*ctrl_desc[cd->controller].N_CONNECT_RESPONSE)(mcrsp->cdid, mcrsp->response, mcrsp->cause); break; } /* disconnect request, actively terminate connection */ case I4B_DISCONNECT_REQ: { msg_discon_req_t *mdr; mdr = (msg_discon_req_t *)data; if((cd = cd_by_cdid(mdr->cdid)) == NULL)/* get cd */ { NDBGL4(L4_ERR, "I4B_DISCONNECT_REQ ioctl, cdid not found!"); error = EINVAL; break; } /* preset causes with our cause */ cd->cause_in = cd->cause_out = mdr->cause; (*ctrl_desc[cd->controller].N_DISCONNECT_REQUEST)(mdr->cdid, mdr->cause); break; } /* controller info request */ case I4B_CTRL_INFO_REQ: { msg_ctrl_info_req_t *mcir; mcir = (msg_ctrl_info_req_t *)data; mcir->ncontroller = nctrl; if(mcir->controller > nctrl) { mcir->ctrl_type = -1; mcir->card_type = -1; } else { mcir->ctrl_type = ctrl_desc[mcir->controller].ctrl_type; mcir->card_type = ctrl_desc[mcir->controller].card_type; mcir->nbch = ctrl_desc[mcir->controller].nbch; if(ctrl_desc[mcir->controller].ctrl_type == CTRL_PASSIVE) mcir->tei = ctrl_desc[mcir->controller].tei; else mcir->tei = -1; } break; } /* dial response */ case I4B_DIALOUT_RESP: { drvr_link_t *dlt = NULL; msg_dialout_resp_t *mdrsp; mdrsp = (msg_dialout_resp_t *)data; switch(mdrsp->driver) { #if NI4BIPR > 0 case BDRV_IPR: dlt = ipr_ret_linktab(mdrsp->driver_unit); break; #endif #if NI4BISPPP > 0 case BDRV_ISPPP: dlt = i4bisppp_ret_linktab(mdrsp->driver_unit); break; #endif #if NI4BTEL > 0 case BDRV_TEL: dlt = tel_ret_linktab(mdrsp->driver_unit); break; #endif #if NI4BING > 0 case BDRV_ING: dlt = ing_ret_linktab(mdrsp->driver_unit); break; #endif } if(dlt != NULL) (*dlt->dial_response)(mdrsp->driver_unit, mdrsp->stat, mdrsp->cause); break; } /* update timeout value */ case I4B_TIMEOUT_UPD: { msg_timeout_upd_t *mtu; mtu = (msg_timeout_upd_t *)data; NDBGL4(L4_TIMO, "I4B_TIMEOUT_UPD ioctl, alg %d, unit %d, idle %d, early %d!", mtu->shorthold_data.shorthold_algorithm, mtu->shorthold_data.unitlen_time, mtu->shorthold_data.idle_time, mtu->shorthold_data.earlyhup_time); if((cd = cd_by_cdid(mtu->cdid)) == NULL)/* get cd */ { NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, cdid not found!"); error = EINVAL; break; } switch( mtu->shorthold_data.shorthold_algorithm ) { case SHA_FIXU: /* * For this algorithm unitlen_time, * idle_time and earlyhup_time are used. */ if(!(mtu->shorthold_data.unitlen_time >= 0 && mtu->shorthold_data.idle_time >= 0 && mtu->shorthold_data.earlyhup_time >= 0)) { NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid args for fix unit algorithm!"); error = EINVAL; } break; case SHA_VARU: /* * For this algorithm unitlen_time and * idle_time are used. both must be * positive integers. earlyhup_time is * not used and must be 0. */ if(!(mtu->shorthold_data.unitlen_time > 0 && mtu->shorthold_data.idle_time >= 0 && mtu->shorthold_data.earlyhup_time == 0)) { NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid args for var unit algorithm!"); error = EINVAL; } break; default: NDBGL4(L4_ERR, "I4B_TIMEOUT_UPD ioctl, invalid algorithm!"); error = EINVAL; break; } /* * any error set above requires us to break * out of the outer switch */ if(error != 0) break; crit_enter(); cd->shorthold_data.shorthold_algorithm = mtu->shorthold_data.shorthold_algorithm; cd->shorthold_data.unitlen_time = mtu->shorthold_data.unitlen_time; cd->shorthold_data.idle_time = mtu->shorthold_data.idle_time; cd->shorthold_data.earlyhup_time = mtu->shorthold_data.earlyhup_time; crit_exit(); break; } /* soft enable/disable interface */ case I4B_UPDOWN_IND: { msg_updown_ind_t *mui; mui = (msg_updown_ind_t *)data; #if NI4BIPR > 0 if(mui->driver == BDRV_IPR) { drvr_link_t *dlt; dlt = ipr_ret_linktab(mui->driver_unit); (*dlt->updown_ind)(mui->driver_unit, mui->updown); } #endif break; } /* send ALERT request */ case I4B_ALERT_REQ: { msg_alert_req_t *mar; mar = (msg_alert_req_t *)data; if((cd = cd_by_cdid(mar->cdid)) == NULL) { NDBGL4(L4_ERR, "I4B_ALERT_REQ ioctl, cdid not found!"); error = EINVAL; break; } T400_stop(cd); (*ctrl_desc[cd->controller].N_ALERT_REQUEST)(mar->cdid); break; } /* version/release number request */ case I4B_VR_REQ: { msg_vr_req_t *mvr; mvr = (msg_vr_req_t *)data; mvr->version = VERSION; mvr->release = REL; mvr->step = STEP; break; } /* set D-channel protocol for a controller */ case I4B_PROT_IND: { msg_prot_ind_t *mpi; mpi = (msg_prot_ind_t *)data; ctrl_desc[mpi->controller].protocol = mpi->protocol; break; } /* Download request */ case I4B_CTRL_DOWNLOAD: { struct isdn_dr_prot *prots = NULL, *prots2 = NULL; struct isdn_download_request *r = (struct isdn_download_request*)data; int i; if (r->controller < 0 || r->controller >= nctrl) { error = ENODEV; goto download_done; } if(!ctrl_desc[r->controller].N_DOWNLOAD) { error = ENODEV; goto download_done; } prots = kmalloc(r->numprotos * sizeof(struct isdn_dr_prot), M_DEVBUF, M_WAITOK); prots2 = kmalloc(r->numprotos * sizeof(struct isdn_dr_prot), M_DEVBUF, M_WAITOK); copyin(r->protocols, prots, r->numprotos * sizeof(struct isdn_dr_prot)); for(i = 0; i < r->numprotos; i++) { prots2[i].microcode = kmalloc(prots[i].bytecount, M_DEVBUF, M_WAITOK); copyin(prots[i].microcode, prots2[i].microcode, prots[i].bytecount); prots2[i].bytecount = prots[i].bytecount; } error = ctrl_desc[r->controller].N_DOWNLOAD( ctrl_desc[r->controller].unit, r->numprotos, prots2); download_done: if(prots2) { for(i = 0; i < r->numprotos; i++) { if(prots2[i].microcode) { kfree(prots2[i].microcode, M_DEVBUF); } } kfree(prots2, M_DEVBUF); } if(prots) { kfree(prots, M_DEVBUF); } break; } /* Diagnostic request */ case I4B_ACTIVE_DIAGNOSTIC: { struct isdn_diagnostic_request req, *r = (struct isdn_diagnostic_request*)data; req.in_param = req.out_param = NULL; if (r->controller < 0 || r->controller >= nctrl) { error = ENODEV; goto diag_done; } if(!ctrl_desc[r->controller].N_DIAGNOSTICS) { error = ENODEV; goto diag_done; } memcpy(&req, r, sizeof(req)); if(req.in_param_len) { /* XXX arbitrary limit */ if (req.in_param_len > I4B_ACTIVE_DIAGNOSTIC_MAXPARAMLEN) { error = EINVAL; goto diag_done; } req.in_param = kmalloc(r->in_param_len, M_DEVBUF, M_WAITOK); error = copyin(r->in_param, req.in_param, req.in_param_len); if (error) goto diag_done; } if(req.out_param_len) req.out_param = kmalloc(r->out_param_len, M_DEVBUF, M_WAITOK); error = ctrl_desc[r->controller].N_DIAGNOSTICS(r->controller, &req); if(!error && req.out_param_len) error = copyout(req.out_param, r->out_param, req.out_param_len); diag_done: if(req.in_param) kfree(req.in_param, M_DEVBUF); if(req.out_param) kfree(req.out_param, M_DEVBUF); break; } /* default */ default: error = ENOTTY; break; } return(error); }