diff options
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 = { |