diff options
author | Jukka Rissanen <jukka.rissanen@linux.intel.com> | 2014-09-29 09:37:25 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2014-09-29 11:06:38 -0400 |
commit | 36b3dd250dde5317fa6bb8c9010e1e7ab7f2265a (patch) | |
tree | 66128ae6c14ecaba27c51ea148050a83af87cf50 /net | |
parent | 59790aa2873cb3c32db02c777f08eb19faccf5fa (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.c | 135 |
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 | ||
429 | static int header_create(struct sk_buff *skb, struct net_device *netdev, | 429 | static 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 | |||
494 | static 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 */ |
494 | static int send_pkt(struct l2cap_chan *chan, struct sk_buff *skb, | 511 | static 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) | |||
561 | static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) | 587 | static 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 | ||
603 | static const struct net_device_ops netdev_ops = { | 634 | static const struct net_device_ops netdev_ops = { |