|
@@ -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,10 @@ 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);
|
|
|
+ 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 +158,33 @@ 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;
|
|
|
+ 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,7 +234,7 @@ 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;
|
|
|
|
|
@@ -211,6 +248,9 @@ recv_Bchannel(struct bchannel *bch, unsigned int id)
|
|
|
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;
|
|
@@ -426,7 +466,7 @@ bchannel_get_rxbuf(struct bchannel *bch, int reqlen)
|
|
|
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);
|
|
|
+ recv_Bchannel(bch, 0, true);
|
|
|
} else {
|
|
|
/* on HDLC we have to drop too big frames */
|
|
|
return -EMSGSIZE;
|
|
@@ -435,12 +475,25 @@ bchannel_get_rxbuf(struct bchannel *bch, int reqlen)
|
|
|
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))
|
|
|
- len = reqlen;
|
|
|
- else /* with HDLC we do not know the length yet */
|
|
|
+ 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",
|