aboutsummaryrefslogtreecommitdiffstats
path: root/net/llc/llc_sap.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/llc/llc_sap.c')
-rw-r--r--net/llc/llc_sap.c66
1 files changed, 43 insertions, 23 deletions
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c
index 008de1fc42ca..39760d013ce2 100644
--- a/net/llc/llc_sap.c
+++ b/net/llc/llc_sap.c
@@ -297,6 +297,17 @@ static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb,
297 llc_sap_state_process(sap, skb); 297 llc_sap_state_process(sap, skb);
298} 298}
299 299
300static inline bool llc_dgram_match(const struct llc_sap *sap,
301 const struct llc_addr *laddr,
302 const struct sock *sk)
303{
304 struct llc_sock *llc = llc_sk(sk);
305
306 return sk->sk_type == SOCK_DGRAM &&
307 llc->laddr.lsap == laddr->lsap &&
308 llc_mac_match(llc->laddr.mac, laddr->mac);
309}
310
300/** 311/**
301 * llc_lookup_dgram - Finds dgram socket for the local sap/mac 312 * llc_lookup_dgram - Finds dgram socket for the local sap/mac
302 * @sap: SAP 313 * @sap: SAP
@@ -309,25 +320,41 @@ static struct sock *llc_lookup_dgram(struct llc_sap *sap,
309 const struct llc_addr *laddr) 320 const struct llc_addr *laddr)
310{ 321{
311 struct sock *rc; 322 struct sock *rc;
312 struct hlist_node *node; 323 struct hlist_nulls_node *node;
313 324
314 read_lock_bh(&sap->sk_list.lock); 325 rcu_read_lock_bh();
315 sk_for_each(rc, node, &sap->sk_list.list) { 326again:
316 struct llc_sock *llc = llc_sk(rc); 327 sk_nulls_for_each_rcu(rc, node, &sap->sk_list) {
317 328 if (llc_dgram_match(sap, laddr, rc)) {
318 if (rc->sk_type == SOCK_DGRAM && 329 /* Extra checks required by SLAB_DESTROY_BY_RCU */
319 llc->laddr.lsap == laddr->lsap && 330 if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt)))
320 llc_mac_match(llc->laddr.mac, laddr->mac)) { 331 goto again;
321 sock_hold(rc); 332 if (unlikely(llc_sk(rc)->sap != sap ||
333 !llc_dgram_match(sap, laddr, rc))) {
334 sock_put(rc);
335 continue;
336 }
322 goto found; 337 goto found;
323 } 338 }
324 } 339 }
325 rc = NULL; 340 rc = NULL;
326found: 341found:
327 read_unlock_bh(&sap->sk_list.lock); 342 rcu_read_unlock_bh();
328 return rc; 343 return rc;
329} 344}
330 345
346static inline bool llc_mcast_match(const struct llc_sap *sap,
347 const struct llc_addr *laddr,
348 const struct sk_buff *skb,
349 const struct sock *sk)
350{
351 struct llc_sock *llc = llc_sk(sk);
352
353 return sk->sk_type == SOCK_DGRAM &&
354 llc->laddr.lsap == laddr->lsap &&
355 llc->dev == skb->dev;
356}
357
331/** 358/**
332 * llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets. 359 * llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets.
333 * @sap: SAP 360 * @sap: SAP
@@ -341,20 +368,13 @@ static void llc_sap_mcast(struct llc_sap *sap,
341 struct sk_buff *skb) 368 struct sk_buff *skb)
342{ 369{
343 struct sock *sk; 370 struct sock *sk;
344 struct hlist_node *node; 371 struct hlist_nulls_node *node;
345 372
346 read_lock_bh(&sap->sk_list.lock); 373 spin_lock_bh(&sap->sk_lock);
347 sk_for_each(sk, node, &sap->sk_list.list) { 374 sk_nulls_for_each_rcu(sk, node, &sap->sk_list) {
348 struct llc_sock *llc = llc_sk(sk);
349 struct sk_buff *skb1; 375 struct sk_buff *skb1;
350 376
351 if (sk->sk_type != SOCK_DGRAM) 377 if (!llc_mcast_match(sap, laddr, skb, sk))
352 continue;
353
354 if (llc->laddr.lsap != laddr->lsap)
355 continue;
356
357 if (llc->dev != skb->dev)
358 continue; 378 continue;
359 379
360 skb1 = skb_clone(skb, GFP_ATOMIC); 380 skb1 = skb_clone(skb, GFP_ATOMIC);
@@ -365,7 +385,7 @@ static void llc_sap_mcast(struct llc_sap *sap,
365 llc_sap_rcv(sap, skb1, sk); 385 llc_sap_rcv(sap, skb1, sk);
366 sock_put(sk); 386 sock_put(sk);
367 } 387 }
368 read_unlock_bh(&sap->sk_list.lock); 388 spin_unlock_bh(&sap->sk_lock);
369} 389}
370 390
371 391