summaryrefslogtreecommitdiffstats
path: root/drivers/isdn
diff options
context:
space:
mode:
authorKarsten Keil <keil@b1-systems.de>2015-10-21 08:18:39 -0400
committerDavid S. Miller <davem@davemloft.net>2015-10-22 10:23:19 -0400
commitc96356a9baa2e3d628caf52f3b83df1968628b5f (patch)
tree01de4f3ad8098331f6c94d54c77b82398c92b3ec /drivers/isdn
parentc7a7c95e8e18a3598c4d0f99c35e69dce591daf1 (diff)
mISDN: fix OOM condition for sending queued I-Frames
The old code did not check the return value of skb_clone(). The extra skb_clone() is not needed at all, if using skb_realloc_headroom() instead, which gives us a private copy with enough headroom as well. We need to requeue the original skb if the call failed, because we cannot inform upper layers about the data loss. Restructure the code to minimise rollback effort if it happens. This fix kernel bug #86091 Thanks to Insu Yun <wuninsu@gmail.com> to remind me on this issue. Signed-off-by: Karsten Keil <keil@b1-systems.de> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/isdn')
-rw-r--r--drivers/isdn/mISDN/layer2.c54
1 files changed, 20 insertions, 34 deletions
diff --git a/drivers/isdn/mISDN/layer2.c b/drivers/isdn/mISDN/layer2.c
index 949cabb88f1c..5eb380a25903 100644
--- a/drivers/isdn/mISDN/layer2.c
+++ b/drivers/isdn/mISDN/layer2.c
@@ -1476,7 +1476,7 @@ static void
1476l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) 1476l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
1477{ 1477{
1478 struct layer2 *l2 = fi->userdata; 1478 struct layer2 *l2 = fi->userdata;
1479 struct sk_buff *skb, *nskb, *oskb; 1479 struct sk_buff *skb, *nskb;
1480 u_char header[MAX_L2HEADER_LEN]; 1480 u_char header[MAX_L2HEADER_LEN];
1481 u_int i, p1; 1481 u_int i, p1;
1482 1482
@@ -1486,48 +1486,34 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
1486 skb = skb_dequeue(&l2->i_queue); 1486 skb = skb_dequeue(&l2->i_queue);
1487 if (!skb) 1487 if (!skb)
1488 return; 1488 return;
1489
1490 if (test_bit(FLG_MOD128, &l2->flag))
1491 p1 = (l2->vs - l2->va) % 128;
1492 else
1493 p1 = (l2->vs - l2->va) % 8;
1494 p1 = (p1 + l2->sow) % l2->window;
1495 if (l2->windowar[p1]) {
1496 printk(KERN_WARNING "%s: l2 try overwrite ack queue entry %d\n",
1497 mISDNDevName4ch(&l2->ch), p1);
1498 dev_kfree_skb(l2->windowar[p1]);
1499 }
1500 l2->windowar[p1] = skb;
1501 i = sethdraddr(l2, header, CMD); 1489 i = sethdraddr(l2, header, CMD);
1502 if (test_bit(FLG_MOD128, &l2->flag)) { 1490 if (test_bit(FLG_MOD128, &l2->flag)) {
1503 header[i++] = l2->vs << 1; 1491 header[i++] = l2->vs << 1;
1504 header[i++] = l2->vr << 1; 1492 header[i++] = l2->vr << 1;
1493 } else
1494 header[i++] = (l2->vr << 5) | (l2->vs << 1);
1495 nskb = skb_realloc_headroom(skb, i);
1496 if (!nskb) {
1497 printk(KERN_WARNING "%s: no headroom(%d) copy for IFrame\n",
1498 mISDNDevName4ch(&l2->ch), i);
1499 skb_queue_head(&l2->i_queue, skb);
1500 return;
1501 }
1502 if (test_bit(FLG_MOD128, &l2->flag)) {
1503 p1 = (l2->vs - l2->va) % 128;
1505 l2->vs = (l2->vs + 1) % 128; 1504 l2->vs = (l2->vs + 1) % 128;
1506 } else { 1505 } else {
1507 header[i++] = (l2->vr << 5) | (l2->vs << 1); 1506 p1 = (l2->vs - l2->va) % 8;
1508 l2->vs = (l2->vs + 1) % 8; 1507 l2->vs = (l2->vs + 1) % 8;
1509 } 1508 }
1510 1509 p1 = (p1 + l2->sow) % l2->window;
1511 nskb = skb_clone(skb, GFP_ATOMIC); 1510 if (l2->windowar[p1]) {
1512 p1 = skb_headroom(nskb); 1511 printk(KERN_WARNING "%s: l2 try overwrite ack queue entry %d\n",
1513 if (p1 >= i) 1512 mISDNDevName4ch(&l2->ch), p1);
1514 memcpy(skb_push(nskb, i), header, i); 1513 dev_kfree_skb(l2->windowar[p1]);
1515 else {
1516 printk(KERN_WARNING
1517 "%s: L2 pull_iqueue skb header(%d/%d) too short\n",
1518 mISDNDevName4ch(&l2->ch), i, p1);
1519 oskb = nskb;
1520 nskb = mI_alloc_skb(oskb->len + i, GFP_ATOMIC);
1521 if (!nskb) {
1522 dev_kfree_skb(oskb);
1523 printk(KERN_WARNING "%s: no skb mem in %s\n",
1524 mISDNDevName4ch(&l2->ch), __func__);
1525 return;
1526 }
1527 memcpy(skb_put(nskb, i), header, i);
1528 memcpy(skb_put(nskb, oskb->len), oskb->data, oskb->len);
1529 dev_kfree_skb(oskb);
1530 } 1514 }
1515 l2->windowar[p1] = skb;
1516 memcpy(skb_push(nskb, i), header, i);
1531 l2down(l2, PH_DATA_REQ, l2_newid(l2), nskb); 1517 l2down(l2, PH_DATA_REQ, l2_newid(l2), nskb);
1532 test_and_clear_bit(FLG_ACK_PEND, &l2->flag); 1518 test_and_clear_bit(FLG_ACK_PEND, &l2->flag);
1533 if (!test_and_set_bit(FLG_T200_RUN, &l2->flag)) { 1519 if (!test_and_set_bit(FLG_T200_RUN, &l2->flag)) {