aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/ndisc.c
diff options
context:
space:
mode:
authorYOSHIFUJI Hideaki / 吉藤英明 <yoshfuji@linux-ipv6.org>2013-01-21 01:48:49 -0500
committerDavid S. Miller <davem@davemloft.net>2013-01-21 13:33:16 -0500
commit2ce13576144ade3e9340efce9620a6dd338aedc7 (patch)
tree96e3dca4ed2b8427211439804608ced30c7556f8 /net/ipv6/ndisc.c
parent5135e633f92ab4deb3600a30cbbec6e0929fc8a4 (diff)
ndisc: Calculate message body length and option length separately.
Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/ndisc.c')
-rw-r--r--net/ipv6/ndisc.c20
1 files changed, 11 insertions, 9 deletions
diff --git a/net/ipv6/ndisc.c b/net/ipv6/ndisc.c
index 62b1415bec25..c2b16ffeb1a8 100644
--- a/net/ipv6/ndisc.c
+++ b/net/ipv6/ndisc.c
@@ -426,6 +426,7 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
426 struct sk_buff *skb; 426 struct sk_buff *skb;
427 struct icmp6hdr *hdr; 427 struct icmp6hdr *hdr;
428 int len; 428 int len;
429 int optlen = 0;
429 u8 *opt; 430 u8 *opt;
430 431
431 if (!dev->addr_len) 432 if (!dev->addr_len)
@@ -433,13 +434,13 @@ static struct sk_buff *ndisc_build_skb(struct net_device *dev,
433 434
434 len = sizeof(struct icmp6hdr) + (target ? sizeof(*target) : 0); 435 len = sizeof(struct icmp6hdr) + (target ? sizeof(*target) : 0);
435 if (llinfo) 436 if (llinfo)
436 len += ndisc_opt_addr_space(dev); 437 optlen += ndisc_opt_addr_space(dev);
437 438
438 skb = ndisc_alloc_skb(dev, len); 439 skb = ndisc_alloc_skb(dev, len + optlen);
439 if (!skb) 440 if (!skb)
440 return NULL; 441 return NULL;
441 442
442 skb_put(skb, len); 443 skb_put(skb, len + optlen);
443 444
444 hdr = (struct icmp6hdr *)skb_transport_header(skb); 445 hdr = (struct icmp6hdr *)skb_transport_header(skb);
445 memcpy(hdr, icmp6h, sizeof(*hdr)); 446 memcpy(hdr, icmp6h, sizeof(*hdr));
@@ -1396,7 +1397,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
1396 struct net_device *dev = skb->dev; 1397 struct net_device *dev = skb->dev;
1397 struct net *net = dev_net(dev); 1398 struct net *net = dev_net(dev);
1398 struct sock *sk = net->ipv6.ndisc_sk; 1399 struct sock *sk = net->ipv6.ndisc_sk;
1399 int len = sizeof(struct rd_msg); 1400 int optlen = 0;
1400 struct inet_peer *peer; 1401 struct inet_peer *peer;
1401 struct sk_buff *buff; 1402 struct sk_buff *buff;
1402 struct rd_msg *msg; 1403 struct rd_msg *msg;
@@ -1463,7 +1464,7 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
1463 memcpy(ha_buf, neigh->ha, dev->addr_len); 1464 memcpy(ha_buf, neigh->ha, dev->addr_len);
1464 read_unlock_bh(&neigh->lock); 1465 read_unlock_bh(&neigh->lock);
1465 ha = ha_buf; 1466 ha = ha_buf;
1466 len += ndisc_opt_addr_space(dev); 1467 optlen += ndisc_opt_addr_space(dev);
1467 } else 1468 } else
1468 read_unlock_bh(&neigh->lock); 1469 read_unlock_bh(&neigh->lock);
1469 1470
@@ -1471,15 +1472,16 @@ void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
1471 } 1472 }
1472 1473
1473 rd_len = min_t(unsigned int, 1474 rd_len = min_t(unsigned int,
1474 IPV6_MIN_MTU-sizeof(struct ipv6hdr)-len, skb->len + 8); 1475 IPV6_MIN_MTU - sizeof(struct ipv6hdr) - sizeof(*msg) - optlen,
1476 skb->len + 8);
1475 rd_len &= ~0x7; 1477 rd_len &= ~0x7;
1476 len += rd_len; 1478 optlen += rd_len;
1477 1479
1478 buff = ndisc_alloc_skb(dev, len); 1480 buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);
1479 if (!buff) 1481 if (!buff)
1480 goto release; 1482 goto release;
1481 1483
1482 skb_put(buff, len); 1484 skb_put(buff, sizeof(*msg) + optlen);
1483 msg = (struct rd_msg *)icmp6_hdr(buff); 1485 msg = (struct rd_msg *)icmp6_hdr(buff);
1484 1486
1485 memset(&msg->icmph, 0, sizeof(struct icmp6hdr)); 1487 memset(&msg->icmph, 0, sizeof(struct icmp6hdr));