aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/llc/llc_sap.c59
1 files changed, 51 insertions, 8 deletions
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}