aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/llc_if.h4
-rw-r--r--net/llc/llc_sap.c59
2 files changed, 55 insertions, 8 deletions
diff --git a/include/net/llc_if.h b/include/net/llc_if.h
index a05d04ac4513..c608812a8e89 100644
--- a/include/net/llc_if.h
+++ b/include/net/llc_if.h
@@ -79,6 +79,10 @@ static inline int llc_addrany(const struct llc_addr *addr)
79 return llc_mac_null(addr->mac) && !addr->lsap; 79 return llc_mac_null(addr->mac) && !addr->lsap;
80} 80}
81 81
82static inline int llc_mac_multicast(const u8 *mac)
83{
84 return is_multicast_ether_addr(mac);
85}
82/** 86/**
83 * llc_mac_match - determines if two mac addresses are the same 87 * llc_mac_match - determines if two mac addresses are the same
84 * @mac1: First mac address to compare. 88 * @mac1: First mac address to compare.
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c
index 4029ceee9b91..20c4eb5c1ac6 100644
--- a/net/llc/llc_sap.c
+++ b/net/llc/llc_sap.c
@@ -282,7 +282,7 @@ static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb)
282 * mac, and local sap. Returns pointer for socket found, %NULL otherwise. 282 * mac, and local sap. Returns pointer for socket found, %NULL otherwise.
283 */ 283 */
284static struct sock *llc_lookup_dgram(struct llc_sap *sap, 284static struct sock *llc_lookup_dgram(struct llc_sap *sap,
285 struct llc_addr *laddr) 285 const struct llc_addr *laddr)
286{ 286{
287 struct sock *rc; 287 struct sock *rc;
288 struct hlist_node *node; 288 struct hlist_node *node;
@@ -304,19 +304,62 @@ found:
304 return rc; 304 return rc;
305} 305}
306 306
307/**
308 * llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets.
309 * @sap: SAP
310 * @laddr: address of local LLC (MAC + SAP)
311 *
312 * Search socket list of the SAP and finds connections with same sap.
313 * Deliver clone to each.
314 */
315static void llc_sap_mcast(struct llc_sap *sap,
316 const struct llc_addr *laddr,
317 struct sk_buff *skb)
318{
319 struct sock *sk;
320 struct hlist_node *node;
321
322 read_lock_bh(&sap->sk_list.lock);
323 sk_for_each(sk, node, &sap->sk_list.list) {
324 struct llc_sock *llc = llc_sk(sk);
325 struct sk_buff *skb1;
326
327 if (sk->sk_type != SOCK_DGRAM)
328 continue;
329
330 if (llc->laddr.lsap != laddr->lsap)
331 continue;
332
333 skb1 = skb_clone(skb, GFP_ATOMIC);
334 if (!skb1)
335 break;
336
337 sock_hold(sk);
338 skb_set_owner_r(skb1, sk);
339 llc_sap_rcv(sap, skb1);
340 sock_put(sk);
341 }
342 read_unlock_bh(&sap->sk_list.lock);
343}
344
345
307void llc_sap_handler(struct llc_sap *sap, struct sk_buff *skb) 346void llc_sap_handler(struct llc_sap *sap, struct sk_buff *skb)
308{ 347{
309 struct llc_addr laddr; 348 struct llc_addr laddr;
310 struct sock *sk;
311 349
312 llc_pdu_decode_da(skb, laddr.mac); 350 llc_pdu_decode_da(skb, laddr.mac);
313 llc_pdu_decode_dsap(skb, &laddr.lsap); 351 llc_pdu_decode_dsap(skb, &laddr.lsap);
314 352
315 sk = llc_lookup_dgram(sap, &laddr); 353 if (llc_mac_multicast(laddr.mac)) {
316 if (sk) { 354 llc_sap_mcast(sap, &laddr, skb);
317 skb_set_owner_r(skb, sk);
318 llc_sap_rcv(sap, skb);
319 sock_put(sk);
320 } else
321 kfree_skb(skb); 355 kfree_skb(skb);
356 } else {
357 struct sock *sk = llc_lookup_dgram(sap, &laddr);
358 if (sk) {
359 skb_set_owner_r(skb, sk);
360 llc_sap_rcv(sap, skb);
361 sock_put(sk);
362 } else
363 kfree_skb(skb);
364 }
322} 365}