aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/isdn
diff options
context:
space:
mode:
authorKarsten Keil <keil@b1-systems.de>2015-10-21 08:18:38 -0400
committerDavid S. Miller <davem@davemloft.net>2015-10-22 10:23:19 -0400
commitc7a7c95e8e18a3598c4d0f99c35e69dce591daf1 (patch)
tree14d13afeeb24e7890b42109bac28e95520fcfde6 /drivers/isdn
parent4ef7ea9195ea73262cd9730fb54e1eb726da157b (diff)
ISDN: fix OOM condition for sending queued I-Frames
The skb_clone() return value was not checked and the skb_realloc_headroom() usage was wrong, the old skb was not freed. It turned out, that the skb_clone is not needed at all, the skb_realloc_headroom() will create a private copy with enough headroom and the original SKB can be used for the ACK queue. We need to requeue the original skb if the call failed, since the upper layer cannot be informed about memory shortage. 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/hisax/isdnl2.c20
1 files changed, 8 insertions, 12 deletions
diff --git a/drivers/isdn/hisax/isdnl2.c b/drivers/isdn/hisax/isdnl2.c
index 18accb0a79cc..c53a53f6efb6 100644
--- a/drivers/isdn/hisax/isdnl2.c
+++ b/drivers/isdn/hisax/isdnl2.c
@@ -1247,7 +1247,7 @@ static void
1247l2_pull_iqueue(struct FsmInst *fi, int event, void *arg) 1247l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
1248{ 1248{
1249 struct PStack *st = fi->userdata; 1249 struct PStack *st = fi->userdata;
1250 struct sk_buff *skb; 1250 struct sk_buff *skb, *nskb;
1251 struct Layer2 *l2 = &st->l2; 1251 struct Layer2 *l2 = &st->l2;
1252 u_char header[MAX_HEADER_LEN]; 1252 u_char header[MAX_HEADER_LEN];
1253 int i, hdr_space_needed; 1253 int i, hdr_space_needed;
@@ -1262,14 +1262,10 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
1262 return; 1262 return;
1263 1263
1264 hdr_space_needed = l2headersize(l2, 0); 1264 hdr_space_needed = l2headersize(l2, 0);
1265 if (hdr_space_needed > skb_headroom(skb)) { 1265 nskb = skb_realloc_headroom(skb, hdr_space_needed);
1266 struct sk_buff *orig_skb = skb; 1266 if (!nskb) {
1267 1267 skb_queue_head(&l2->i_queue, skb);
1268 skb = skb_realloc_headroom(skb, hdr_space_needed); 1268 return;
1269 if (!skb) {
1270 dev_kfree_skb(orig_skb);
1271 return;
1272 }
1273 } 1269 }
1274 spin_lock_irqsave(&l2->lock, flags); 1270 spin_lock_irqsave(&l2->lock, flags);
1275 if (test_bit(FLG_MOD128, &l2->flag)) 1271 if (test_bit(FLG_MOD128, &l2->flag))
@@ -1282,7 +1278,7 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
1282 p1); 1278 p1);
1283 dev_kfree_skb(l2->windowar[p1]); 1279 dev_kfree_skb(l2->windowar[p1]);
1284 } 1280 }
1285 l2->windowar[p1] = skb_clone(skb, GFP_ATOMIC); 1281 l2->windowar[p1] = skb;
1286 1282
1287 i = sethdraddr(&st->l2, header, CMD); 1283 i = sethdraddr(&st->l2, header, CMD);
1288 1284
@@ -1295,8 +1291,8 @@ l2_pull_iqueue(struct FsmInst *fi, int event, void *arg)
1295 l2->vs = (l2->vs + 1) % 8; 1291 l2->vs = (l2->vs + 1) % 8;
1296 } 1292 }
1297 spin_unlock_irqrestore(&l2->lock, flags); 1293 spin_unlock_irqrestore(&l2->lock, flags);
1298 memcpy(skb_push(skb, i), header, i); 1294 memcpy(skb_push(nskb, i), header, i);
1299 st->l2.l2l1(st, PH_PULL | INDICATION, skb); 1295 st->l2.l2l1(st, PH_PULL | INDICATION, nskb);
1300 test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag); 1296 test_and_clear_bit(FLG_ACK_PEND, &st->l2.flag);
1301 if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) { 1297 if (!test_and_set_bit(FLG_T200_RUN, &st->l2.flag)) {
1302 FsmDelTimer(&st->l2.t203, 13); 1298 FsmDelTimer(&st->l2.t203, 13);