diff options
author | Cong Wang <amwang@redhat.com> | 2013-06-02 11:00:52 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-06-03 03:28:44 -0400 |
commit | 9a99d4a50cb8ce516adf0f2436138d4c8e6e4535 (patch) | |
tree | f8854a80373f9288f1ee27a8d0ab54d46b256a57 /net/ipv4/icmp.c | |
parent | 08578d8d4eb76b7afe314fa03abe167761462fe4 (diff) |
icmp: avoid allocating large struct on stack
struct icmp_bxm is a large struct, reduce stack usage
by allocating it on heap.
Cc: Eric Dumazet <eric.dumazet@gmail.com>
Cc: Joe Perches <joe@perches.com>
Cc: David S. Miller <davem@davemloft.net>
Signed-off-by: Cong Wang <amwang@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/icmp.c')
-rw-r--r-- | net/ipv4/icmp.c | 40 |
1 files changed, 23 insertions, 17 deletions
diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 2864ca33bedc..5f7d11a45871 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c | |||
@@ -482,7 +482,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) | |||
482 | { | 482 | { |
483 | struct iphdr *iph; | 483 | struct iphdr *iph; |
484 | int room; | 484 | int room; |
485 | struct icmp_bxm icmp_param; | 485 | struct icmp_bxm *icmp_param; |
486 | struct rtable *rt = skb_rtable(skb_in); | 486 | struct rtable *rt = skb_rtable(skb_in); |
487 | struct ipcm_cookie ipc; | 487 | struct ipcm_cookie ipc; |
488 | struct flowi4 fl4; | 488 | struct flowi4 fl4; |
@@ -558,9 +558,13 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) | |||
558 | } | 558 | } |
559 | } | 559 | } |
560 | 560 | ||
561 | icmp_param = kmalloc(sizeof(*icmp_param), GFP_ATOMIC); | ||
562 | if (!icmp_param) | ||
563 | return; | ||
564 | |||
561 | sk = icmp_xmit_lock(net); | 565 | sk = icmp_xmit_lock(net); |
562 | if (sk == NULL) | 566 | if (sk == NULL) |
563 | return; | 567 | goto out_free; |
564 | 568 | ||
565 | /* | 569 | /* |
566 | * Construct source address and options. | 570 | * Construct source address and options. |
@@ -586,7 +590,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) | |||
586 | IPTOS_PREC_INTERNETCONTROL) : | 590 | IPTOS_PREC_INTERNETCONTROL) : |
587 | iph->tos; | 591 | iph->tos; |
588 | 592 | ||
589 | if (ip_options_echo(&icmp_param.replyopts.opt.opt, skb_in)) | 593 | if (ip_options_echo(&icmp_param->replyopts.opt.opt, skb_in)) |
590 | goto out_unlock; | 594 | goto out_unlock; |
591 | 595 | ||
592 | 596 | ||
@@ -594,19 +598,19 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) | |||
594 | * Prepare data for ICMP header. | 598 | * Prepare data for ICMP header. |
595 | */ | 599 | */ |
596 | 600 | ||
597 | icmp_param.data.icmph.type = type; | 601 | icmp_param->data.icmph.type = type; |
598 | icmp_param.data.icmph.code = code; | 602 | icmp_param->data.icmph.code = code; |
599 | icmp_param.data.icmph.un.gateway = info; | 603 | icmp_param->data.icmph.un.gateway = info; |
600 | icmp_param.data.icmph.checksum = 0; | 604 | icmp_param->data.icmph.checksum = 0; |
601 | icmp_param.skb = skb_in; | 605 | icmp_param->skb = skb_in; |
602 | icmp_param.offset = skb_network_offset(skb_in); | 606 | icmp_param->offset = skb_network_offset(skb_in); |
603 | inet_sk(sk)->tos = tos; | 607 | inet_sk(sk)->tos = tos; |
604 | ipc.addr = iph->saddr; | 608 | ipc.addr = iph->saddr; |
605 | ipc.opt = &icmp_param.replyopts.opt; | 609 | ipc.opt = &icmp_param->replyopts.opt; |
606 | ipc.tx_flags = 0; | 610 | ipc.tx_flags = 0; |
607 | 611 | ||
608 | rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos, | 612 | rt = icmp_route_lookup(net, &fl4, skb_in, iph, saddr, tos, |
609 | type, code, &icmp_param); | 613 | type, code, icmp_param); |
610 | if (IS_ERR(rt)) | 614 | if (IS_ERR(rt)) |
611 | goto out_unlock; | 615 | goto out_unlock; |
612 | 616 | ||
@@ -618,19 +622,21 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info) | |||
618 | room = dst_mtu(&rt->dst); | 622 | room = dst_mtu(&rt->dst); |
619 | if (room > 576) | 623 | if (room > 576) |
620 | room = 576; | 624 | room = 576; |
621 | room -= sizeof(struct iphdr) + icmp_param.replyopts.opt.opt.optlen; | 625 | room -= sizeof(struct iphdr) + icmp_param->replyopts.opt.opt.optlen; |
622 | room -= sizeof(struct icmphdr); | 626 | room -= sizeof(struct icmphdr); |
623 | 627 | ||
624 | icmp_param.data_len = skb_in->len - icmp_param.offset; | 628 | icmp_param->data_len = skb_in->len - icmp_param->offset; |
625 | if (icmp_param.data_len > room) | 629 | if (icmp_param->data_len > room) |
626 | icmp_param.data_len = room; | 630 | icmp_param->data_len = room; |
627 | icmp_param.head_len = sizeof(struct icmphdr); | 631 | icmp_param->head_len = sizeof(struct icmphdr); |
628 | 632 | ||
629 | icmp_push_reply(&icmp_param, &fl4, &ipc, &rt); | 633 | icmp_push_reply(icmp_param, &fl4, &ipc, &rt); |
630 | ende: | 634 | ende: |
631 | ip_rt_put(rt); | 635 | ip_rt_put(rt); |
632 | out_unlock: | 636 | out_unlock: |
633 | icmp_xmit_unlock(sk); | 637 | icmp_xmit_unlock(sk); |
638 | out_free: | ||
639 | kfree(icmp_param); | ||
634 | out:; | 640 | out:; |
635 | } | 641 | } |
636 | EXPORT_SYMBOL(icmp_send); | 642 | EXPORT_SYMBOL(icmp_send); |