diff options
Diffstat (limited to 'net/bluetooth/6lowpan.c')
-rw-r--r-- | net/bluetooth/6lowpan.c | 54 |
1 files changed, 28 insertions, 26 deletions
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index a7cd23f00bde..9d41de1ec90f 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c @@ -1,14 +1,7 @@ +// SPDX-License-Identifier: GPL-2.0-only /* Copyright (c) 2013-2014 Intel Corp. - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License version 2 and - only version 2 as published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. */ #include <linux/if_arp.h> @@ -167,30 +160,25 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_btle_dev *dev, struct in6_addr *daddr, struct sk_buff *skb) { - struct lowpan_peer *peer; - struct in6_addr *nexthop; struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); int count = atomic_read(&dev->peer_count); + const struct in6_addr *nexthop; + struct lowpan_peer *peer; + struct neighbour *neigh; BT_DBG("peers %d addr %pI6c rt %p", count, daddr, rt); - /* If we have multiple 6lowpan peers, then check where we should - * send the packet. If only one peer exists, then we can send the - * packet right away. - */ - if (count == 1) { - rcu_read_lock(); - peer = list_first_or_null_rcu(&dev->peers, struct lowpan_peer, - list); - rcu_read_unlock(); - return peer; - } - if (!rt) { - nexthop = &lowpan_cb(skb)->gw; - - if (ipv6_addr_any(nexthop)) - return NULL; + if (ipv6_addr_any(&lowpan_cb(skb)->gw)) { + /* There is neither route nor gateway, + * probably the destination is a direct peer. + */ + nexthop = daddr; + } else { + /* There is a known gateway + */ + nexthop = &lowpan_cb(skb)->gw; + } } else { nexthop = rt6_nexthop(rt, daddr); @@ -216,6 +204,20 @@ static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_btle_dev *dev, } } + /* use the neighbour cache for matching addresses assigned by SLAAC + */ + neigh = __ipv6_neigh_lookup(dev->netdev, nexthop); + if (neigh) { + list_for_each_entry_rcu(peer, &dev->peers, list) { + if (!memcmp(neigh->ha, peer->lladdr, ETH_ALEN)) { + neigh_release(neigh); + rcu_read_unlock(); + return peer; + } + } + neigh_release(neigh); + } + rcu_read_unlock(); return NULL; |