diff options
Diffstat (limited to 'drivers/isdn/mISDN')
-rw-r--r-- | drivers/isdn/mISDN/core.c | 16 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp.h | 4 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_cmx.c | 19 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_core.c | 1 | ||||
-rw-r--r-- | drivers/isdn/mISDN/dsp_dtmf.c | 19 | ||||
-rw-r--r-- | drivers/isdn/mISDN/hwchannel.c | 162 | ||||
-rw-r--r-- | drivers/isdn/mISDN/l1oip_core.c | 2 | ||||
-rw-r--r-- | drivers/isdn/mISDN/layer1.c | 36 | ||||
-rw-r--r-- | drivers/isdn/mISDN/layer2.c | 120 | ||||
-rw-r--r-- | drivers/isdn/mISDN/tei.c | 72 |
10 files changed, 362 insertions, 89 deletions
diff --git a/drivers/isdn/mISDN/core.c b/drivers/isdn/mISDN/core.c index a24530f05db..c401634c00e 100644 --- a/drivers/isdn/mISDN/core.c +++ b/drivers/isdn/mISDN/core.c @@ -355,6 +355,22 @@ mISDN_unregister_Bprotocol(struct Bprotocol *bp) } EXPORT_SYMBOL(mISDN_unregister_Bprotocol); +static const char *msg_no_channel = "<no channel>"; +static const char *msg_no_stack = "<no stack>"; +static const char *msg_no_stackdev = "<no stack device>"; + +const char *mISDNDevName4ch(struct mISDNchannel *ch) +{ + if (!ch) + return msg_no_channel; + if (!ch->st) + return msg_no_stack; + if (!ch->st->dev) + return msg_no_stackdev; + return dev_name(&ch->st->dev->dev); +}; +EXPORT_SYMBOL(mISDNDevName4ch); + static int mISDNInit(void) { diff --git a/drivers/isdn/mISDN/dsp.h b/drivers/isdn/mISDN/dsp.h index afe4173ae00..fc1733a0884 100644 --- a/drivers/isdn/mISDN/dsp.h +++ b/drivers/isdn/mISDN/dsp.h @@ -76,7 +76,9 @@ extern u8 dsp_silence; #define MAX_SECONDS_JITTER_CHECK 5 extern struct timer_list dsp_spl_tl; -extern u32 dsp_spl_jiffies; + +/* the datatype need to match jiffies datatype */ +extern unsigned long dsp_spl_jiffies; /* the structure of conferences: * diff --git a/drivers/isdn/mISDN/dsp_cmx.c b/drivers/isdn/mISDN/dsp_cmx.c index 334feab060a..a4f05c54c32 100644 --- a/drivers/isdn/mISDN/dsp_cmx.c +++ b/drivers/isdn/mISDN/dsp_cmx.c @@ -742,8 +742,8 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) member->dsp->pcm_slot_tx, member->dsp->pcm_bank_tx, member->dsp->pcm_bank_rx); - conf->hardware = 0; - conf->software = 1; + conf->hardware = 1; + conf->software = tx_data; return; } /* find a new slot */ @@ -834,8 +834,8 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) nextm->dsp->name, member->dsp->pcm_slot_tx, member->dsp->pcm_slot_rx); - conf->hardware = 0; - conf->software = 1; + conf->hardware = 1; + conf->software = tx_data; return; } /* find two new slot */ @@ -939,8 +939,11 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) /* for more than two members.. */ /* if all members already have the same conference */ - if (all_conf) + if (all_conf) { + conf->hardware = 1; + conf->software = tx_data; return; + } /* * if there is an existing conference, but not all members have joined @@ -1013,6 +1016,8 @@ dsp_cmx_hardware(struct dsp_conf *conf, struct dsp *dsp) dsp_cmx_hw_message(member->dsp, MISDN_CTRL_HFC_CONF_JOIN, current_conf, 0, 0, 0); } + conf->hardware = 1; + conf->software = tx_data; return; } @@ -1328,7 +1333,7 @@ dsp_cmx_send_member(struct dsp *dsp, int len, s32 *c, int members) } if (dsp->conf && dsp->conf->software && dsp->conf->hardware) tx_data_only = 1; - if (dsp->conf->software && dsp->echo.hardware) + if (dsp->echo.software && dsp->echo.hardware) tx_data_only = 1; } @@ -1619,7 +1624,7 @@ send_packet: static u32 jittercount; /* counter for jitter check */ struct timer_list dsp_spl_tl; -u32 dsp_spl_jiffies; /* calculate the next time to fire */ +unsigned long dsp_spl_jiffies; /* calculate the next time to fire */ static u16 dsp_count; /* last sample count */ static int dsp_count_valid; /* if we have last sample count */ diff --git a/drivers/isdn/mISDN/dsp_core.c b/drivers/isdn/mISDN/dsp_core.c index 2ac2d7a25a9..28c99c623bc 100644 --- a/drivers/isdn/mISDN/dsp_core.c +++ b/drivers/isdn/mISDN/dsp_core.c @@ -268,6 +268,7 @@ dsp_fill_empty(struct dsp *dsp) } cq.op = MISDN_CTRL_FILL_EMPTY; cq.p1 = 1; + cq.p2 = dsp_silence; if (dsp->ch.peer->ctrl(dsp->ch.peer, CONTROL_CHANNEL, &cq)) { printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n", __func__); diff --git a/drivers/isdn/mISDN/dsp_dtmf.c b/drivers/isdn/mISDN/dsp_dtmf.c index 887860bdc63..642f30be5ce 100644 --- a/drivers/isdn/mISDN/dsp_dtmf.c +++ b/drivers/isdn/mISDN/dsp_dtmf.c @@ -222,16 +222,25 @@ coefficients: goto storedigit; } - if (dsp_debug & DEBUG_DSP_DTMFCOEFF) + if (dsp_debug & DEBUG_DSP_DTMFCOEFF) { + s32 tresh_100 = tresh/100; + + if (tresh_100 == 0) { + tresh_100 = 1; + printk(KERN_DEBUG + "tresh(%d) too small set tresh/100 to 1\n", + tresh); + } printk(KERN_DEBUG "a %3d %3d %3d %3d %3d %3d %3d %3d" " tr:%3d r %3d %3d %3d %3d %3d %3d %3d %3d\n", result[0] / 10000, result[1] / 10000, result[2] / 10000, result[3] / 10000, result[4] / 10000, result[5] / 10000, result[6] / 10000, result[7] / 10000, tresh / 10000, - result[0] / (tresh / 100), result[1] / (tresh / 100), - result[2] / (tresh / 100), result[3] / (tresh / 100), - result[4] / (tresh / 100), result[5] / (tresh / 100), - result[6] / (tresh / 100), result[7] / (tresh / 100)); + result[0] / (tresh_100), result[1] / (tresh_100), + result[2] / (tresh_100), result[3] / (tresh_100), + result[4] / (tresh_100), result[5] / (tresh_100), + result[6] / (tresh_100), result[7] / (tresh_100)); + } /* calc digit (lowgroup/highgroup) */ lowgroup = -1; diff --git a/drivers/isdn/mISDN/hwchannel.c b/drivers/isdn/mISDN/hwchannel.c index c74c363554c..ef34fd40867 100644 --- a/drivers/isdn/mISDN/hwchannel.c +++ b/drivers/isdn/mISDN/hwchannel.c @@ -81,10 +81,16 @@ mISDN_initdchannel(struct dchannel *ch, int maxlen, void *phf) EXPORT_SYMBOL(mISDN_initdchannel); int -mISDN_initbchannel(struct bchannel *ch, int maxlen) +mISDN_initbchannel(struct bchannel *ch, unsigned short maxlen, + unsigned short minlen) { ch->Flags = 0; + ch->minlen = minlen; + ch->next_minlen = minlen; + ch->init_minlen = minlen; ch->maxlen = maxlen; + ch->next_maxlen = maxlen; + ch->init_maxlen = maxlen; ch->hw = NULL; ch->rx_skb = NULL; ch->tx_skb = NULL; @@ -134,6 +140,14 @@ mISDN_clear_bchannel(struct bchannel *ch) test_and_clear_bit(FLG_TX_BUSY, &ch->Flags); test_and_clear_bit(FLG_TX_NEXT, &ch->Flags); test_and_clear_bit(FLG_ACTIVE, &ch->Flags); + test_and_clear_bit(FLG_FILLEMPTY, &ch->Flags); + test_and_clear_bit(FLG_TX_EMPTY, &ch->Flags); + test_and_clear_bit(FLG_RX_OFF, &ch->Flags); + ch->dropcnt = 0; + ch->minlen = ch->init_minlen; + ch->next_minlen = ch->init_minlen; + ch->maxlen = ch->init_maxlen; + ch->next_maxlen = ch->init_maxlen; } EXPORT_SYMBOL(mISDN_clear_bchannel); @@ -148,6 +162,51 @@ mISDN_freebchannel(struct bchannel *ch) } EXPORT_SYMBOL(mISDN_freebchannel); +int +mISDN_ctrl_bchannel(struct bchannel *bch, struct mISDN_ctrl_req *cq) +{ + int ret = 0; + + switch (cq->op) { + case MISDN_CTRL_GETOP: + cq->op = MISDN_CTRL_RX_BUFFER | MISDN_CTRL_FILL_EMPTY | + MISDN_CTRL_RX_OFF; + break; + case MISDN_CTRL_FILL_EMPTY: + if (cq->p1) { + memset(bch->fill, cq->p2 & 0xff, MISDN_BCH_FILL_SIZE); + test_and_set_bit(FLG_FILLEMPTY, &bch->Flags); + } else { + test_and_clear_bit(FLG_FILLEMPTY, &bch->Flags); + } + break; + case MISDN_CTRL_RX_OFF: + /* read back dropped byte count */ + cq->p2 = bch->dropcnt; + if (cq->p1) + test_and_set_bit(FLG_RX_OFF, &bch->Flags); + else + test_and_clear_bit(FLG_RX_OFF, &bch->Flags); + bch->dropcnt = 0; + break; + case MISDN_CTRL_RX_BUFFER: + if (cq->p2 > MISDN_CTRL_RX_SIZE_IGNORE) + bch->next_maxlen = cq->p2; + if (cq->p1 > MISDN_CTRL_RX_SIZE_IGNORE) + bch->next_minlen = cq->p1; + /* we return the old values */ + cq->p1 = bch->minlen; + cq->p2 = bch->maxlen; + break; + default: + pr_info("mISDN unhandled control %x operation\n", cq->op); + ret = -EINVAL; + break; + } + return ret; +} +EXPORT_SYMBOL(mISDN_ctrl_bchannel); + static inline u_int get_sapi_tei(u_char *p) { @@ -197,24 +256,37 @@ recv_Echannel(struct dchannel *ech, struct dchannel *dch) EXPORT_SYMBOL(recv_Echannel); void -recv_Bchannel(struct bchannel *bch, unsigned int id) +recv_Bchannel(struct bchannel *bch, unsigned int id, bool force) { struct mISDNhead *hh; - hh = mISDN_HEAD_P(bch->rx_skb); - hh->prim = PH_DATA_IND; - hh->id = id; - if (bch->rcount >= 64) { - printk(KERN_WARNING "B-channel %p receive queue overflow, " - "flushing!\n", bch); - skb_queue_purge(&bch->rqueue); - bch->rcount = 0; + /* if allocation did fail upper functions still may call us */ + if (unlikely(!bch->rx_skb)) return; + if (unlikely(!bch->rx_skb->len)) { + /* we have no data to send - this may happen after recovery + * from overflow or too small allocation. + * We need to free the buffer here */ + dev_kfree_skb(bch->rx_skb); + bch->rx_skb = NULL; + } else { + if (test_bit(FLG_TRANSPARENT, &bch->Flags) && + (bch->rx_skb->len < bch->minlen) && !force) + return; + hh = mISDN_HEAD_P(bch->rx_skb); + hh->prim = PH_DATA_IND; + hh->id = id; + if (bch->rcount >= 64) { + printk(KERN_WARNING + "B%d receive queue overflow - flushing!\n", + bch->nr); + skb_queue_purge(&bch->rqueue); + } + bch->rcount++; + skb_queue_tail(&bch->rqueue, bch->rx_skb); + bch->rx_skb = NULL; + schedule_event(bch, FLG_RECVQUEUE); } - bch->rcount++; - skb_queue_tail(&bch->rqueue, bch->rx_skb); - bch->rx_skb = NULL; - schedule_event(bch, FLG_RECVQUEUE); } EXPORT_SYMBOL(recv_Bchannel); @@ -272,7 +344,7 @@ get_next_dframe(struct dchannel *dch) } EXPORT_SYMBOL(get_next_dframe); -void +static void confirm_Bsend(struct bchannel *bch) { struct sk_buff *skb; @@ -294,7 +366,6 @@ confirm_Bsend(struct bchannel *bch) skb_queue_tail(&bch->rqueue, skb); schedule_event(bch, FLG_RECVQUEUE); } -EXPORT_SYMBOL(confirm_Bsend); int get_next_bframe(struct bchannel *bch) @@ -305,8 +376,8 @@ get_next_bframe(struct bchannel *bch) if (bch->tx_skb) { bch->next_skb = NULL; test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); - if (!test_bit(FLG_TRANSPARENT, &bch->Flags)) - confirm_Bsend(bch); /* not for transparent */ + /* confirm imediately to allow next data */ + confirm_Bsend(bch); return 1; } else { test_and_clear_bit(FLG_TX_NEXT, &bch->Flags); @@ -395,7 +466,62 @@ bchannel_senddata(struct bchannel *ch, struct sk_buff *skb) /* write to fifo */ ch->tx_skb = skb; ch->tx_idx = 0; + confirm_Bsend(ch); return 1; } } EXPORT_SYMBOL(bchannel_senddata); + +/* The function allocates a new receive skb on demand with a size for the + * requirements of the current protocol. It returns the tailroom of the + * receive skb or an error. + */ +int +bchannel_get_rxbuf(struct bchannel *bch, int reqlen) +{ + int len; + + if (bch->rx_skb) { + len = skb_tailroom(bch->rx_skb); + if (len < reqlen) { + pr_warning("B%d no space for %d (only %d) bytes\n", + bch->nr, reqlen, len); + if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { + /* send what we have now and try a new buffer */ + recv_Bchannel(bch, 0, true); + } else { + /* on HDLC we have to drop too big frames */ + return -EMSGSIZE; + } + } else { + return len; + } + } + /* update current min/max length first */ + if (unlikely(bch->maxlen != bch->next_maxlen)) + bch->maxlen = bch->next_maxlen; + if (unlikely(bch->minlen != bch->next_minlen)) + bch->minlen = bch->next_minlen; + if (unlikely(reqlen > bch->maxlen)) + return -EMSGSIZE; + if (test_bit(FLG_TRANSPARENT, &bch->Flags)) { + if (reqlen >= bch->minlen) { + len = reqlen; + } else { + len = 2 * bch->minlen; + if (len > bch->maxlen) + len = bch->maxlen; + } + } else { + /* with HDLC we do not know the length yet */ + len = bch->maxlen; + } + bch->rx_skb = mI_alloc_skb(len, GFP_ATOMIC); + if (!bch->rx_skb) { + pr_warning("B%d receive no memory for %d bytes\n", + bch->nr, len); + len = -ENOMEM; + } + return len; +} +EXPORT_SYMBOL(bchannel_get_rxbuf); diff --git a/drivers/isdn/mISDN/l1oip_core.c b/drivers/isdn/mISDN/l1oip_core.c index 0f88acf1185..db50f788855 100644 --- a/drivers/isdn/mISDN/l1oip_core.c +++ b/drivers/isdn/mISDN/l1oip_core.c @@ -1420,7 +1420,7 @@ init_card(struct l1oip *hc, int pri, int bundle) bch->nr = i + ch; bch->slot = i + ch; bch->debug = debug; - mISDN_initbchannel(bch, MAX_DATA_MEM); + mISDN_initbchannel(bch, MAX_DATA_MEM, 0); bch->hw = hc; bch->ch.send = handle_bmsg; bch->ch.ctrl = l1oip_bctrl; diff --git a/drivers/isdn/mISDN/layer1.c b/drivers/isdn/mISDN/layer1.c index 0fc49b37551..bebc57b7213 100644 --- a/drivers/isdn/mISDN/layer1.c +++ b/drivers/isdn/mISDN/layer1.c @@ -28,13 +28,15 @@ static u_int *debug; struct layer1 { u_long Flags; struct FsmInst l1m; - struct FsmTimer timer; + struct FsmTimer timer3; + struct FsmTimer timerX; int delay; + int t3_value; struct dchannel *dch; dchannel_l1callback *dcb; }; -#define TIMER3_VALUE 7000 +#define TIMER3_DEFAULT_VALUE 7000 static struct Fsm l1fsm_s = {NULL, 0, 0, NULL, NULL}; @@ -134,7 +136,7 @@ l1_deact_req_s(struct FsmInst *fi, int event, void *arg) struct layer1 *l1 = fi->userdata; mISDN_FsmChangeState(fi, ST_L1_F3); - mISDN_FsmRestartTimer(&l1->timer, 550, EV_TIMER_DEACT, NULL, 2); + mISDN_FsmRestartTimer(&l1->timerX, 550, EV_TIMER_DEACT, NULL, 2); test_and_set_bit(FLG_L1_DEACTTIMER, &l1->Flags); } @@ -179,11 +181,11 @@ l1_info4_ind(struct FsmInst *fi, int event, void *arg) mISDN_FsmChangeState(fi, ST_L1_F7); l1->dcb(l1->dch, INFO3_P8); if (test_and_clear_bit(FLG_L1_DEACTTIMER, &l1->Flags)) - mISDN_FsmDelTimer(&l1->timer, 4); + mISDN_FsmDelTimer(&l1->timerX, 4); if (!test_bit(FLG_L1_ACTIVATED, &l1->Flags)) { if (test_and_clear_bit(FLG_L1_T3RUN, &l1->Flags)) - mISDN_FsmDelTimer(&l1->timer, 3); - mISDN_FsmRestartTimer(&l1->timer, 110, EV_TIMER_ACT, NULL, 2); + mISDN_FsmDelTimer(&l1->timer3, 3); + mISDN_FsmRestartTimer(&l1->timerX, 110, EV_TIMER_ACT, NULL, 2); test_and_set_bit(FLG_L1_ACTTIMER, &l1->Flags); } } @@ -201,7 +203,7 @@ l1_timer3(struct FsmInst *fi, int event, void *arg) } if (l1->l1m.state != ST_L1_F6) { mISDN_FsmChangeState(fi, ST_L1_F3); - l1->dcb(l1->dch, HW_POWERUP_REQ); + /* do not force anything here, we need send INFO 0 */ } } @@ -233,8 +235,9 @@ l1_activate_s(struct FsmInst *fi, int event, void *arg) { struct layer1 *l1 = fi->userdata; - mISDN_FsmRestartTimer(&l1->timer, TIMER3_VALUE, EV_TIMER3, NULL, 2); + mISDN_FsmRestartTimer(&l1->timer3, l1->t3_value, EV_TIMER3, NULL, 2); test_and_set_bit(FLG_L1_T3RUN, &l1->Flags); + /* Tell HW to send INFO 1 */ l1->dcb(l1->dch, HW_RESET_REQ); } @@ -302,7 +305,8 @@ static struct FsmNode L1SFnList[] = static void release_l1(struct layer1 *l1) { - mISDN_FsmDelTimer(&l1->timer, 0); + mISDN_FsmDelTimer(&l1->timerX, 0); + mISDN_FsmDelTimer(&l1->timer3, 0); if (l1->dch) l1->dch->l1 = NULL; module_put(THIS_MODULE); @@ -356,6 +360,16 @@ l1_event(struct layer1 *l1, u_int event) release_l1(l1); break; default: + if ((event & ~HW_TIMER3_VMASK) == HW_TIMER3_VALUE) { + int val = event & HW_TIMER3_VMASK; + + if (val < 5) + val = 5; + if (val > 30) + val = 30; + l1->t3_value = val; + break; + } if (*debug & DEBUG_L1) printk(KERN_DEBUG "%s %x unhandled\n", __func__, event); @@ -377,13 +391,15 @@ create_l1(struct dchannel *dch, dchannel_l1callback *dcb) { nl1->l1m.fsm = &l1fsm_s; nl1->l1m.state = ST_L1_F3; nl1->Flags = 0; + nl1->t3_value = TIMER3_DEFAULT_VALUE; nl1->l1m.debug = *debug & DEBUG_L1_FSM; nl1->l1m.userdata = nl1; nl1->l1m.userint = 0; nl1->l1m.printdebug = l1m_debug; nl1->dch = dch; nl1->dcb = dcb; - mISDN_FsmInitTimer(&nl1->l1m, &nl1->timer); + mISDN_FsmInitTimer(&nl1->l1m, &nl1->timer3); + mISDN_FsmInitTimer(&nl1->l1m, &nl1->timerX); __module_get(THIS_MODULE); dch->l1 = nl1; return 0; diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c index 39d7375fa55..0dc8abca140 100644 --- a/drivers/isdn/mISDN/layer2.c +++ b/drivers/isdn/mISDN/layer2.c @@ -58,6 +58,8 @@ enum { EV_L1_DEACTIVATE, EV_L2_T200, EV_L2_T203, + EV_L2_T200I, + EV_L2_T203I, EV_L2_SET_OWN_BUSY, EV_L2_CLEAR_OWN_BUSY, EV_L2_FRAME_ERROR, @@ -86,6 +88,8 @@ static char *strL2Event[] = "EV_L1_DEACTIVATE", "EV_L2_T200", "EV_L2_T203", + "EV_L2_T200I", + "EV_L2_T203I", "EV_L2_SET_OWN_BUSY", "EV_L2_CLEAR_OWN_BUSY", "EV_L2_FRAME_ERROR", @@ -106,8 +110,8 @@ l2m_debug(struct FsmInst *fi, char *fmt, ...) vaf.fmt = fmt; vaf.va = &va; - printk(KERN_DEBUG "l2 (sapi %d tei %d): %pV\n", - l2->sapi, l2->tei, &vaf); + printk(KERN_DEBUG "%s l2 (sapi %d tei %d): %pV\n", + mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei, &vaf); va_end(va); } @@ -150,7 +154,8 @@ l2up(struct layer2 *l2, u_int prim, struct sk_buff *skb) mISDN_HEAD_ID(skb) = (l2->ch.nr << 16) | l2->ch.addr; err = l2->up->send(l2->up, skb); if (err) { - printk(KERN_WARNING "%s: err=%d\n", __func__, err); + printk(KERN_WARNING "%s: dev %s err=%d\n", __func__, + mISDNDevName4ch(&l2->ch), err); dev_kfree_skb(skb); } } @@ -174,7 +179,8 @@ l2up_create(struct layer2 *l2, u_int prim, int len, void *arg) memcpy(skb_put(skb, len), arg, len); err = l2->up->send(l2->up, skb); if (err) { - printk(KERN_WARNING "%s: err=%d\n", __func__, err); + printk(KERN_WARNING "%s: dev %s err=%d\n", __func__, + mISDNDevName4ch(&l2->ch), err); dev_kfree_skb(skb); } } @@ -185,7 +191,8 @@ l2down_skb(struct layer2 *l2, struct sk_buff *skb) { ret = l2->ch.recv(l2->ch.peer, skb); if (ret && (*debug & DEBUG_L2_RECV)) - printk(KERN_DEBUG "l2down_skb: ret(%d)\n", ret); + printk(KERN_DEBUG "l2down_skb: dev %s ret(%d)\n", + mISDNDevName4ch(&l2->ch), ret); return ret; } @@ -276,12 +283,37 @@ ph_data_confirm(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) { return ret; } +static void +l2_timeout(struct FsmInst *fi, int event, void *arg) +{ + struct layer2 *l2 = fi->userdata; + struct sk_buff *skb; + struct mISDNhead *hh; + + skb = mI_alloc_skb(0, GFP_ATOMIC); + if (!skb) { + printk(KERN_WARNING "%s: L2(%d,%d) nr:%x timer %s no skb\n", + mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei, + l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203"); + return; + } + hh = mISDN_HEAD_P(skb); + hh->prim = event == EV_L2_T200 ? DL_TIMER200_IND : DL_TIMER203_IND; + hh->id = l2->ch.nr; + if (*debug & DEBUG_TIMER) + printk(KERN_DEBUG "%s: L2(%d,%d) nr:%x timer %s expired\n", + mISDNDevName4ch(&l2->ch), l2->sapi, l2->tei, + l2->ch.nr, event == EV_L2_T200 ? "T200" : "T203"); + if (l2->ch.st) + l2->ch.st->own.recv(&l2->ch.st->own, skb); +} + static int l2mgr(struct layer2 *l2, u_int prim, void *arg) { long c = (long)arg; - printk(KERN_WARNING - "l2mgr: addr:%x prim %x %c\n", l2->id, prim, (char)c); + printk(KERN_WARNING "l2mgr: dev %s addr:%x prim %x %c\n", + mISDNDevName4ch(&l2->ch), l2->id, prim, (char)c); if (test_bit(FLG_LAPD, &l2->flag) && !test_bit(FLG_FIXED_TEI, &l2->flag)) { switch (c) { @@ -603,8 +635,8 @@ send_uframe(struct layer2 *l2, struct sk_buff *skb, u_char cmd, u_char cr) else { skb = mI_alloc_skb(i, GFP_ATOMIC); if (!skb) { - printk(KERN_WARNING "%s: can't alloc skbuff\n", - __func__); + printk(KERN_WARNING "%s: can't alloc skbuff in %s\n", + mISDNDevName4ch(&l2->ch), __func__); return; } } @@ -1089,8 +1121,8 @@ enquiry_cr(struct layer2 *l2, u_char typ, u_char cr, u_char pf) tmp[i++] = (l2->vr << 5) | typ | (pf ? 0x10 : 0); skb = mI_alloc_skb(i, GFP_ATOMIC); if (!skb) { - printk(KERN_WARNING - "isdnl2 can't alloc sbbuff for enquiry_cr\n"); + printk(KERN_WARNING "%s: isdnl2 can't alloc sbbuff in %s\n", + mISDNDevName4ch(&l2->ch), __func__); return; } memcpy(skb_put(skb, i), tmp, i); @@ -1150,7 +1182,7 @@ invoke_retransmission(struct layer2 *l2, unsigned int nr) else printk(KERN_WARNING "%s: windowar[%d] is NULL\n", - __func__, p1); + mISDNDevName4ch(&l2->ch), p1); l2->windowar[p1] = NULL; } mISDN_FsmEvent(&l2->l2m, EV_L2_ACK_PULL, NULL); @@ -1461,8 +1493,8 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) p1 = (l2->vs - l2->va) % 8; p1 = (p1 + l2->sow) % l2->window; if (l2->windowar[p1]) { - printk(KERN_WARNING "isdnl2 try overwrite ack queue entry %d\n", - p1); + printk(KERN_WARNING "%s: l2 try overwrite ack queue entry %d\n", + mISDNDevName4ch(&l2->ch), p1); dev_kfree_skb(l2->windowar[p1]); } l2->windowar[p1] = skb; @@ -1482,12 +1514,14 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) memcpy(skb_push(nskb, i), header, i); else { printk(KERN_WARNING - "isdnl2 pull_iqueue skb header(%d/%d) too short\n", i, p1); + "%s: L2 pull_iqueue skb header(%d/%d) too short\n", + mISDNDevName4ch(&l2->ch), i, p1); oskb = nskb; nskb = mI_alloc_skb(oskb->len + i, GFP_ATOMIC); if (!nskb) { dev_kfree_skb(oskb); - printk(KERN_WARNING "%s: no skb mem\n", __func__); + printk(KERN_WARNING "%s: no skb mem in %s\n", + mISDNDevName4ch(&l2->ch), __func__); return; } memcpy(skb_put(nskb, i), header, i); @@ -1814,11 +1848,16 @@ static struct FsmNode L2FnList[] = {ST_L2_8, EV_L2_SUPER, l2_st8_got_super}, {ST_L2_7, EV_L2_I, l2_got_iframe}, {ST_L2_8, EV_L2_I, l2_got_iframe}, - {ST_L2_5, EV_L2_T200, l2_st5_tout_200}, - {ST_L2_6, EV_L2_T200, l2_st6_tout_200}, - {ST_L2_7, EV_L2_T200, l2_st7_tout_200}, - {ST_L2_8, EV_L2_T200, l2_st8_tout_200}, - {ST_L2_7, EV_L2_T203, l2_st7_tout_203}, + {ST_L2_5, EV_L2_T200, l2_timeout}, + {ST_L2_6, EV_L2_T200, l2_timeout}, + {ST_L2_7, EV_L2_T200, l2_timeout}, + {ST_L2_8, EV_L2_T200, l2_timeout}, + {ST_L2_7, EV_L2_T203, l2_timeout}, + {ST_L2_5, EV_L2_T200I, l2_st5_tout_200}, + {ST_L2_6, EV_L2_T200I, l2_st6_tout_200}, + {ST_L2_7, EV_L2_T200I, l2_st7_tout_200}, + {ST_L2_8, EV_L2_T200I, l2_st8_tout_200}, + {ST_L2_7, EV_L2_T203I, l2_st7_tout_203}, {ST_L2_7, EV_L2_ACK_PULL, l2_pull_iqueue}, {ST_L2_7, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, {ST_L2_8, EV_L2_SET_OWN_BUSY, l2_set_own_busy}, @@ -1858,7 +1897,8 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) ptei = *datap++; if ((psapi & 1) || !(ptei & 1)) { printk(KERN_WARNING - "l2 D-channel frame wrong EA0/EA1\n"); + "%s l2 D-channel frame wrong EA0/EA1\n", + mISDNDevName4ch(&l2->ch)); return ret; } psapi >>= 2; @@ -1867,7 +1907,8 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) /* not our business */ if (*debug & DEBUG_L2) printk(KERN_DEBUG "%s: sapi %d/%d mismatch\n", - __func__, psapi, l2->sapi); + mISDNDevName4ch(&l2->ch), psapi, + l2->sapi); dev_kfree_skb(skb); return 0; } @@ -1875,7 +1916,7 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) /* not our business */ if (*debug & DEBUG_L2) printk(KERN_DEBUG "%s: tei %d/%d mismatch\n", - __func__, ptei, l2->tei); + mISDNDevName4ch(&l2->ch), ptei, l2->tei); dev_kfree_skb(skb); return 0; } @@ -1916,7 +1957,8 @@ ph_data_indication(struct layer2 *l2, struct mISDNhead *hh, struct sk_buff *skb) } else c = 'L'; if (c) { - printk(KERN_WARNING "l2 D-channel frame error %c\n", c); + printk(KERN_WARNING "%s:l2 D-channel frame error %c\n", + mISDNDevName4ch(&l2->ch), c); mISDN_FsmEvent(&l2->l2m, EV_L2_FRAME_ERROR, (void *)(long)c); } return ret; @@ -1930,8 +1972,17 @@ l2_send(struct mISDNchannel *ch, struct sk_buff *skb) int ret = -EINVAL; if (*debug & DEBUG_L2_RECV) - printk(KERN_DEBUG "%s: prim(%x) id(%x) sapi(%d) tei(%d)\n", - __func__, hh->prim, hh->id, l2->sapi, l2->tei); + printk(KERN_DEBUG "%s: %s prim(%x) id(%x) sapi(%d) tei(%d)\n", + __func__, mISDNDevName4ch(&l2->ch), hh->prim, hh->id, + l2->sapi, l2->tei); + if (hh->prim == DL_INTERN_MSG) { + struct mISDNhead *chh = hh + 1; /* saved copy */ + + *hh = *chh; + if (*debug & DEBUG_L2_RECV) + printk(KERN_DEBUG "%s: prim(%x) id(%x) internal msg\n", + mISDNDevName4ch(&l2->ch), hh->prim, hh->id); + } switch (hh->prim) { case PH_DATA_IND: ret = ph_data_indication(l2, hh, skb); @@ -1987,6 +2038,12 @@ l2_send(struct mISDNchannel *ch, struct sk_buff *skb) ret = mISDN_FsmEvent(&l2->l2m, EV_L2_DL_RELEASE_REQ, skb); break; + case DL_TIMER200_IND: + mISDN_FsmEvent(&l2->l2m, EV_L2_T200I, NULL); + break; + case DL_TIMER203_IND: + mISDN_FsmEvent(&l2->l2m, EV_L2_T203I, NULL); + break; default: if (*debug & DEBUG_L2) l2m_debug(&l2->l2m, "l2 unknown pr %04x", @@ -2005,7 +2062,8 @@ tei_l2(struct layer2 *l2, u_int cmd, u_long arg) int ret = -EINVAL; if (*debug & DEBUG_L2_TEI) - printk(KERN_DEBUG "%s: cmd(%x)\n", __func__, cmd); + printk(KERN_DEBUG "%s: cmd(%x) in %s\n", + mISDNDevName4ch(&l2->ch), cmd, __func__); switch (cmd) { case (MDL_ASSIGN_REQ): ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ASSIGN, (void *)arg); @@ -2018,7 +2076,8 @@ tei_l2(struct layer2 *l2, u_int cmd, u_long arg) break; case (MDL_ERROR_RSP): /* ETS 300-125 5.3.2.1 Test: TC13010 */ - printk(KERN_NOTICE "MDL_ERROR|REQ (tei_l2)\n"); + printk(KERN_NOTICE "%s: MDL_ERROR|REQ (tei_l2)\n", + mISDNDevName4ch(&l2->ch)); ret = mISDN_FsmEvent(&l2->l2m, EV_L2_MDL_ERROR, NULL); break; } @@ -2050,7 +2109,8 @@ l2_ctrl(struct mISDNchannel *ch, u_int cmd, void *arg) u_int info; if (*debug & DEBUG_L2_CTRL) - printk(KERN_DEBUG "%s:(%x)\n", __func__, cmd); + printk(KERN_DEBUG "%s: %s cmd(%x)\n", + mISDNDevName4ch(ch), __func__, cmd); switch (cmd) { case OPEN_CHANNEL: diff --git a/drivers/isdn/mISDN/tei.c b/drivers/isdn/mISDN/tei.c index ba2bc0c776e..be88728f110 100644 --- a/drivers/isdn/mISDN/tei.c +++ b/drivers/isdn/mISDN/tei.c @@ -790,18 +790,23 @@ tei_ph_data_ind(struct teimgr *tm, u_int mt, u_char *dp, int len) static struct layer2 * create_new_tei(struct manager *mgr, int tei, int sapi) { - u_long opt = 0; - u_long flags; - int id; - struct layer2 *l2; + unsigned long opt = 0; + unsigned long flags; + int id; + struct layer2 *l2; + struct channel_req rq; if (!mgr->up) return NULL; if ((tei >= 0) && (tei < 64)) test_and_set_bit(OPTION_L2_FIXEDTEI, &opt); - if (mgr->ch.st->dev->Dprotocols - & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) + if (mgr->ch.st->dev->Dprotocols & ((1 << ISDN_P_TE_E1) | + (1 << ISDN_P_NT_E1))) { test_and_set_bit(OPTION_L2_PMX, &opt); + rq.protocol = ISDN_P_NT_E1; + } else { + rq.protocol = ISDN_P_NT_S0; + } l2 = create_l2(mgr->up, ISDN_P_LAPD_NT, opt, tei, sapi); if (!l2) { printk(KERN_WARNING "%s:no memory for layer2\n", __func__); @@ -836,6 +841,14 @@ create_new_tei(struct manager *mgr, int tei, int sapi) l2->ch.recv = mgr->ch.recv; l2->ch.peer = mgr->ch.peer; l2->ch.ctrl(&l2->ch, OPEN_CHANNEL, NULL); + /* We need open here L1 for the manager as well (refcounting) */ + rq.adr.dev = mgr->ch.st->dev->id; + id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, &rq); + if (id < 0) { + printk(KERN_WARNING "%s: cannot open L1\n", __func__); + l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); + l2 = NULL; + } } return l2; } @@ -978,10 +991,11 @@ TEIrelease(struct layer2 *l2) static int create_teimgr(struct manager *mgr, struct channel_req *crq) { - struct layer2 *l2; - u_long opt = 0; - u_long flags; - int id; + struct layer2 *l2; + unsigned long opt = 0; + unsigned long flags; + int id; + struct channel_req l1rq; if (*debug & DEBUG_L2_TEI) printk(KERN_DEBUG "%s: %s proto(%x) adr(%d %d %d %d)\n", @@ -1016,6 +1030,7 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) if (crq->protocol == ISDN_P_LAPD_TE) test_and_set_bit(MGR_OPT_USER, &mgr->options); } + l1rq.adr = crq->adr; if (mgr->ch.st->dev->Dprotocols & ((1 << ISDN_P_TE_E1) | (1 << ISDN_P_NT_E1))) test_and_set_bit(OPTION_L2_PMX, &opt); @@ -1023,6 +1038,8 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) mgr->up = crq->ch; id = DL_INFO_L2_CONNECT; teiup_create(mgr, DL_INFORMATION_IND, sizeof(id), &id); + if (test_bit(MGR_PH_ACTIVE, &mgr->options)) + teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL); crq->ch = NULL; if (!list_empty(&mgr->layer2)) { read_lock_irqsave(&mgr->lock, flags); @@ -1053,24 +1070,34 @@ create_teimgr(struct manager *mgr, struct channel_req *crq) l2->tm->tei_m.fsm = &teifsmu; l2->tm->tei_m.state = ST_TEI_NOP; l2->tm->tval = 1000; /* T201 1 sec */ + if (test_bit(OPTION_L2_PMX, &opt)) + l1rq.protocol = ISDN_P_TE_E1; + else + l1rq.protocol = ISDN_P_TE_S0; } else { l2->tm->tei_m.fsm = &teifsmn; l2->tm->tei_m.state = ST_TEI_NOP; l2->tm->tval = 2000; /* T202 2 sec */ + if (test_bit(OPTION_L2_PMX, &opt)) + l1rq.protocol = ISDN_P_NT_E1; + else + l1rq.protocol = ISDN_P_NT_S0; } mISDN_FsmInitTimer(&l2->tm->tei_m, &l2->tm->timer); write_lock_irqsave(&mgr->lock, flags); id = get_free_id(mgr); list_add_tail(&l2->list, &mgr->layer2); write_unlock_irqrestore(&mgr->lock, flags); - if (id < 0) { - l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); - } else { + if (id >= 0) { l2->ch.nr = id; l2->up->nr = id; crq->ch = &l2->ch; - id = 0; + /* We need open here L1 for the manager as well (refcounting) */ + id = mgr->ch.st->own.ctrl(&mgr->ch.st->own, OPEN_CHANNEL, + &l1rq); } + if (id < 0) + l2->ch.ctrl(&l2->ch, CLOSE_CHANNEL, NULL); return id; } @@ -1096,12 +1123,16 @@ mgr_send(struct mISDNchannel *ch, struct sk_buff *skb) break; case PH_ACTIVATE_IND: test_and_set_bit(MGR_PH_ACTIVE, &mgr->options); + if (mgr->up) + teiup_create(mgr, PH_ACTIVATE_IND, 0, NULL); mISDN_FsmEvent(&mgr->deact, EV_ACTIVATE_IND, NULL); do_send(mgr); ret = 0; break; case PH_DEACTIVATE_IND: test_and_clear_bit(MGR_PH_ACTIVE, &mgr->options); + if (mgr->up) + teiup_create(mgr, PH_DEACTIVATE_IND, 0, NULL); mISDN_FsmEvent(&mgr->deact, EV_DEACTIVATE_IND, NULL); ret = 0; break; @@ -1263,7 +1294,7 @@ static int mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb) { struct manager *mgr = container_of(ch, struct manager, bcast); - struct mISDNhead *hh = mISDN_HEAD_P(skb); + struct mISDNhead *hhc, *hh = mISDN_HEAD_P(skb); struct sk_buff *cskb = NULL; struct layer2 *l2; u_long flags; @@ -1278,10 +1309,17 @@ mgr_bcast(struct mISDNchannel *ch, struct sk_buff *skb) skb = NULL; } else { if (!cskb) - cskb = skb_copy(skb, GFP_KERNEL); + cskb = skb_copy(skb, GFP_ATOMIC); } if (cskb) { - ret = l2->ch.send(&l2->ch, cskb); + hhc = mISDN_HEAD_P(cskb); + /* save original header behind normal header */ + hhc++; + *hhc = *hh; + hhc--; + hhc->prim = DL_INTERN_MSG; + hhc->id = l2->ch.nr; + ret = ch->st->own.recv(&ch->st->own, cskb); if (ret) { if (*debug & DEBUG_SEND_ERR) printk(KERN_DEBUG |