aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorJukka Rissanen <jukka.rissanen@linux.intel.com>2014-09-29 09:37:25 -0400
committerMarcel Holtmann <marcel@holtmann.org>2014-09-29 11:06:38 -0400
commit36b3dd250dde5317fa6bb8c9010e1e7ab7f2265a (patch)
tree66128ae6c14ecaba27c51ea148050a83af87cf50 /net
parent59790aa2873cb3c32db02c777f08eb19faccf5fa (diff)
Bluetooth: 6lowpan: Ensure header compression does not corrupt IPv6 header
If skb is going to multiple destinations, then make sure that we do not overwrite the common IPv6 headers. So before compressing the IPv6 headers, we copy the skb and that is then sent to 6LoWPAN Bluetooth devices. This is a similar patch as what was done for IEEE 802.154 6LoWPAN in commit f19f4f9525cf3 ("ieee802154: 6lowpan: ensure header compression does not corrupt ipv6 header") Signed-off-by: Jukka Rissanen <jukka.rissanen@linux.intel.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net')
-rw-r--r--net/bluetooth/6lowpan.c135
1 files changed, 83 insertions, 52 deletions
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 5d3e6202da3d..2ec7c84c2000 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -426,38 +426,33 @@ static void convert_dest_bdaddr(struct in6_addr *ip6_daddr,
426 *addr_type = get_addr_type_from_eui64(addr->b[5]); 426 *addr_type = get_addr_type_from_eui64(addr->b[5]);
427} 427}
428 428
429static int header_create(struct sk_buff *skb, struct net_device *netdev, 429static int setup_header(struct sk_buff *skb, struct net_device *netdev,
430 unsigned short type, const void *_daddr, 430 bdaddr_t *peer_addr, u8 *peer_addr_type)
431 const void *_saddr, unsigned int len)
432{ 431{
433 struct ipv6hdr *hdr; 432 struct in6_addr ipv6_daddr;
434 struct lowpan_dev *dev; 433 struct lowpan_dev *dev;
435 struct lowpan_peer *peer; 434 struct lowpan_peer *peer;
436 bdaddr_t addr, *any = BDADDR_ANY; 435 bdaddr_t addr, *any = BDADDR_ANY;
437 u8 *saddr, *daddr = any->b; 436 u8 *daddr = any->b;
438 u8 addr_type; 437 int err, status = 0;
439
440 if (type != ETH_P_IPV6)
441 return -EINVAL;
442
443 hdr = ipv6_hdr(skb);
444 438
445 dev = lowpan_dev(netdev); 439 dev = lowpan_dev(netdev);
446 440
447 if (ipv6_addr_is_multicast(&hdr->daddr)) { 441 memcpy(&ipv6_daddr, &lowpan_cb(skb)->addr, sizeof(ipv6_daddr));
448 memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, 442
449 sizeof(struct in6_addr)); 443 if (ipv6_addr_is_multicast(&ipv6_daddr)) {
450 lowpan_cb(skb)->chan = NULL; 444 lowpan_cb(skb)->chan = NULL;
451 } else { 445 } else {
452 unsigned long flags; 446 unsigned long flags;
447 u8 addr_type;
453 448
454 /* Get destination BT device from skb. 449 /* Get destination BT device from skb.
455 * If there is no such peer then discard the packet. 450 * If there is no such peer then discard the packet.
456 */ 451 */
457 convert_dest_bdaddr(&hdr->daddr, &addr, &addr_type); 452 convert_dest_bdaddr(&ipv6_daddr, &addr, &addr_type);
458 453
459 BT_DBG("dest addr %pMR type %d IP %pI6c", &addr, 454 BT_DBG("dest addr %pMR type %d IP %pI6c", &addr,
460 addr_type, &hdr->daddr); 455 addr_type, &ipv6_daddr);
461 456
462 read_lock_irqsave(&devices_lock, flags); 457 read_lock_irqsave(&devices_lock, flags);
463 peer = peer_lookup_ba(dev, &addr, addr_type); 458 peer = peer_lookup_ba(dev, &addr, addr_type);
@@ -470,7 +465,7 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev,
470 * the destination address. 465 * the destination address.
471 */ 466 */
472 read_lock_irqsave(&devices_lock, flags); 467 read_lock_irqsave(&devices_lock, flags);
473 peer = peer_lookup_dst(dev, &hdr->daddr, skb); 468 peer = peer_lookup_dst(dev, &ipv6_daddr, skb);
474 read_unlock_irqrestore(&devices_lock, flags); 469 read_unlock_irqrestore(&devices_lock, flags);
475 if (!peer) { 470 if (!peer) {
476 BT_DBG("no such peer %pMR found", &addr); 471 BT_DBG("no such peer %pMR found", &addr);
@@ -479,29 +474,56 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev,
479 } 474 }
480 475
481 daddr = peer->eui64_addr; 476 daddr = peer->eui64_addr;
482 477 *peer_addr = addr;
483 memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, 478 *peer_addr_type = addr_type;
484 sizeof(struct in6_addr));
485 lowpan_cb(skb)->chan = peer->chan; 479 lowpan_cb(skb)->chan = peer->chan;
480
481 status = 1;
486 } 482 }
487 483
488 saddr = dev->netdev->dev_addr; 484 lowpan_header_compress(skb, netdev, ETH_P_IPV6, daddr,
485 dev->netdev->dev_addr, skb->len);
486
487 err = dev_hard_header(skb, netdev, ETH_P_IPV6, NULL, NULL, 0);
488 if (err < 0)
489 return err;
490
491 return status;
492}
493
494static int header_create(struct sk_buff *skb, struct net_device *netdev,
495 unsigned short type, const void *_daddr,
496 const void *_saddr, unsigned int len)
497{
498 struct ipv6hdr *hdr;
499
500 if (type != ETH_P_IPV6)
501 return -EINVAL;
502
503 hdr = ipv6_hdr(skb);
504
505 memcpy(&lowpan_cb(skb)->addr, &hdr->daddr, sizeof(struct in6_addr));
489 506
490 return lowpan_header_compress(skb, netdev, type, daddr, saddr, len); 507 return 0;
491} 508}
492 509
493/* Packet to BT LE device */ 510/* Packet to BT LE device */
494static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb, 511static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb,
495 struct net_device *netdev) 512 struct net_device *netdev, bool is_mcast)
496{ 513{
497 struct msghdr msg; 514 struct msghdr msg;
498 struct kvec iv; 515 struct kvec iv;
499 int err; 516 int err;
500 517
501 /* Remember the skb so that we can send EAGAIN to the caller if 518 /* Remember the skb so that we can send EAGAIN to the caller if
502 * we run out of credits. 519 * we run out of credits. This is not done for multicast packets
520 * because we generate mcast packet in this module and are not
521 * really able to remember the skb after this packet is sent.
503 */ 522 */
504 chan->data = skb; 523 if (is_mcast)
524 chan->data = NULL;
525 else
526 chan->data = skb;
505 527
506 memset(&msg, 0, sizeof(msg)); 528 memset(&msg, 0, sizeof(msg));
507 msg.msg_iov = (struct iovec *) &iv; 529 msg.msg_iov = (struct iovec *) &iv;
@@ -549,7 +571,11 @@ static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
549 list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) { 571 list_for_each_entry_safe(pentry, ptmp, &dev->peers, list) {
550 local_skb = skb_clone(skb, GFP_ATOMIC); 572 local_skb = skb_clone(skb, GFP_ATOMIC);
551 573
552 send_pkt(pentry->chan, local_skb, netdev); 574 BT_DBG("xmit %s to %pMR type %d IP %pI6c chan %p",
575 netdev->name,
576 &pentry->chan->dst, pentry->chan->dst_type,
577 &pentry->peer_addr, pentry->chan);
578 send_pkt(pentry->chan, local_skb, netdev, true);
553 579
554 kfree_skb(local_skb); 580 kfree_skb(local_skb);
555 } 581 }
@@ -561,43 +587,48 @@ static void send_mcast_pkt(struct sk_buff *skb, struct net_device *netdev)
561static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) 587static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev)
562{ 588{
563 int err = 0; 589 int err = 0;
564 struct lowpan_dev *dev;
565 struct lowpan_peer *peer;
566 bdaddr_t addr; 590 bdaddr_t addr;
567 u8 addr_type; 591 u8 addr_type;
568 592
569 if (ipv6_addr_is_multicast(&lowpan_cb(skb)->addr)) { 593 /* We must take a copy of the skb before we modify/replace the ipv6
570 /* We need to send the packet to every device 594 * header as the header could be used elsewhere
571 * behind this interface. 595 */
572 */ 596 skb = skb_unshare(skb, GFP_ATOMIC);
573 send_mcast_pkt(skb, netdev); 597 if (!skb)
574 } else { 598 return NET_XMIT_DROP;
575 unsigned long flags;
576
577 convert_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type);
578 dev = lowpan_dev(netdev);
579
580 read_lock_irqsave(&devices_lock, flags);
581 peer = peer_lookup_ba(dev, &addr, addr_type);
582 if (!peer)
583 peer = peer_lookup_dst(dev, &lowpan_cb(skb)->addr, skb);
584 read_unlock_irqrestore(&devices_lock, flags);
585 599
586 BT_DBG("xmit %s to %pMR type %d IP %pI6c peer %p", 600 /* Return values from setup_header()
587 netdev->name, &addr, addr_type, 601 * <0 - error, packet is dropped
588 &lowpan_cb(skb)->addr, peer); 602 * 0 - this is a multicast packet
603 * 1 - this is unicast packet
604 */
605 err = setup_header(skb, netdev, &addr, &addr_type);
606 if (err < 0) {
607 kfree_skb(skb);
608 return NET_XMIT_DROP;
609 }
589 610
590 if (peer && peer->chan) 611 if (err) {
591 err = send_pkt(peer->chan, skb, netdev); 612 if (lowpan_cb(skb)->chan) {
592 else 613 BT_DBG("xmit %s to %pMR type %d IP %pI6c chan %p",
614 netdev->name, &addr, addr_type,
615 &lowpan_cb(skb)->addr, lowpan_cb(skb)->chan);
616 err = send_pkt(lowpan_cb(skb)->chan, skb, netdev,
617 false);
618 } else {
593 err = -ENOENT; 619 err = -ENOENT;
620 }
621 } else {
622 /* We need to send the packet to every device behind this
623 * interface.
624 */
625 send_mcast_pkt(skb, netdev);
594 } 626 }
595 dev_kfree_skb(skb);
596 627
597 if (err) 628 if (err)
598 BT_DBG("ERROR: xmit failed (%d)", err); 629 BT_DBG("ERROR: xmit failed (%d)", err);
599 630
600 return (err < 0) ? NET_XMIT_DROP : err; 631 return err < 0 ? NET_XMIT_DROP : err;
601} 632}
602 633
603static const struct net_device_ops netdev_ops = { 634static const struct net_device_ops netdev_ops = {