diff options
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/6lowpan.c | 65 |
1 files changed, 63 insertions, 2 deletions
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index b229aed3bf9a..0920cb6ed572 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c | |||
@@ -39,6 +39,7 @@ static struct dentry *lowpan_control_debugfs; | |||
39 | 39 | ||
40 | struct skb_cb { | 40 | struct skb_cb { |
41 | struct in6_addr addr; | 41 | struct in6_addr addr; |
42 | struct in6_addr gw; | ||
42 | struct l2cap_chan *chan; | 43 | struct l2cap_chan *chan; |
43 | int status; | 44 | int status; |
44 | }; | 45 | }; |
@@ -158,6 +159,54 @@ static inline struct lowpan_peer *peer_lookup_conn(struct lowpan_dev *dev, | |||
158 | return NULL; | 159 | return NULL; |
159 | } | 160 | } |
160 | 161 | ||
162 | static inline struct lowpan_peer *peer_lookup_dst(struct lowpan_dev *dev, | ||
163 | struct in6_addr *daddr, | ||
164 | struct sk_buff *skb) | ||
165 | { | ||
166 | struct lowpan_peer *peer, *tmp; | ||
167 | struct in6_addr *nexthop; | ||
168 | struct rt6_info *rt = (struct rt6_info *)skb_dst(skb); | ||
169 | int count = atomic_read(&dev->peer_count); | ||
170 | |||
171 | BT_DBG("peers %d addr %pI6c rt %p", count, daddr, rt); | ||
172 | |||
173 | /* If we have multiple 6lowpan peers, then check where we should | ||
174 | * send the packet. If only one peer exists, then we can send the | ||
175 | * packet right away. | ||
176 | */ | ||
177 | if (count == 1) | ||
178 | return list_first_entry(&dev->peers, struct lowpan_peer, | ||
179 | list); | ||
180 | |||
181 | if (!rt) { | ||
182 | nexthop = &lowpan_cb(skb)->gw; | ||
183 | |||
184 | if (ipv6_addr_any(nexthop)) | ||
185 | return NULL; | ||
186 | } else { | ||
187 | nexthop = rt6_nexthop(rt); | ||
188 | |||
189 | /* We need to remember the address because it is needed | ||
190 | * by bt_xmit() when sending the packet. In bt_xmit(), the | ||
191 | * destination routing info is not set. | ||
192 | */ | ||
193 | memcpy(&lowpan_cb(skb)->gw, nexthop, sizeof(struct in6_addr)); | ||
194 | } | ||
195 | |||
196 | BT_DBG("gw %pI6c", nexthop); | ||
197 | |||
198 | list_for_each_entry_safe(peer, tmp, &dev->peers, list) { | ||
199 | BT_DBG("dst addr %pMR dst type %d ip %pI6c", | ||
200 | &peer->chan->dst, peer->chan->dst_type, | ||
201 | &peer->peer_addr); | ||
202 | |||
203 | if (!ipv6_addr_cmp(&peer->peer_addr, nexthop)) | ||
204 | return peer; | ||
205 | } | ||
206 | |||
207 | return NULL; | ||
208 | } | ||
209 | |||
161 | static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn) | 210 | static struct lowpan_peer *lookup_peer(struct l2cap_conn *conn) |
162 | { | 211 | { |
163 | struct lowpan_dev *entry, *tmp; | 212 | struct lowpan_dev *entry, *tmp; |
@@ -415,8 +464,18 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev, | |||
415 | read_unlock_irqrestore(&devices_lock, flags); | 464 | read_unlock_irqrestore(&devices_lock, flags); |
416 | 465 | ||
417 | if (!peer) { | 466 | if (!peer) { |
418 | BT_DBG("no such peer %pMR found", &addr); | 467 | /* The packet might be sent to 6lowpan interface |
419 | return -ENOENT; | 468 | * because of routing (either via default route |
469 | * or user set route) so get peer according to | ||
470 | * the destination address. | ||
471 | */ | ||
472 | read_lock_irqsave(&devices_lock, flags); | ||
473 | peer = peer_lookup_dst(dev, &hdr->daddr, skb); | ||
474 | read_unlock_irqrestore(&devices_lock, flags); | ||
475 | if (!peer) { | ||
476 | BT_DBG("no such peer %pMR found", &addr); | ||
477 | return -ENOENT; | ||
478 | } | ||
420 | } | 479 | } |
421 | 480 | ||
422 | daddr = peer->eui64_addr; | 481 | daddr = peer->eui64_addr; |
@@ -520,6 +579,8 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) | |||
520 | 579 | ||
521 | read_lock_irqsave(&devices_lock, flags); | 580 | read_lock_irqsave(&devices_lock, flags); |
522 | peer = peer_lookup_ba(dev, &addr, addr_type); | 581 | peer = peer_lookup_ba(dev, &addr, addr_type); |
582 | if (!peer) | ||
583 | peer = peer_lookup_dst(dev, &lowpan_cb(skb)->addr, skb); | ||
523 | read_unlock_irqrestore(&devices_lock, flags); | 584 | read_unlock_irqrestore(&devices_lock, flags); |
524 | 585 | ||
525 | BT_DBG("xmit %s to %pMR type %d IP %pI6c peer %p", | 586 | BT_DBG("xmit %s to %pMR type %d IP %pI6c peer %p", |