11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * llc_sap.c - driver routines for SAP component. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Copyright (c) 1997 by Procom Technology, Inc. 51da177e4SLinus Torvalds * 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> 61da177e4SLinus Torvalds * 71da177e4SLinus Torvalds * This program can be redistributed or modified under the terms of the 81da177e4SLinus Torvalds * GNU General Public License as published by the Free Software Foundation. 91da177e4SLinus Torvalds * This program is distributed without any warranty or implied warranty 101da177e4SLinus Torvalds * of merchantability or fitness for a particular purpose. 111da177e4SLinus Torvalds * 121da177e4SLinus Torvalds * See the GNU General Public License for more details. 131da177e4SLinus Torvalds */ 141da177e4SLinus Torvalds 151da177e4SLinus Torvalds #include <net/llc.h> 161da177e4SLinus Torvalds #include <net/llc_if.h> 171da177e4SLinus Torvalds #include <net/llc_conn.h> 181da177e4SLinus Torvalds #include <net/llc_pdu.h> 191da177e4SLinus Torvalds #include <net/llc_sap.h> 201da177e4SLinus Torvalds #include <net/llc_s_ac.h> 211da177e4SLinus Torvalds #include <net/llc_s_ev.h> 221da177e4SLinus Torvalds #include <net/llc_s_st.h> 231da177e4SLinus Torvalds #include <net/sock.h> 24c752f073SArnaldo Carvalho de Melo #include <net/tcp_states.h> 251da177e4SLinus Torvalds #include <linux/llc.h> 261da177e4SLinus Torvalds 27f83f1768SJoonwoo Park static int llc_mac_header_len(unsigned short devtype) 28f83f1768SJoonwoo Park { 29f83f1768SJoonwoo Park switch (devtype) { 30f83f1768SJoonwoo Park case ARPHRD_ETHER: 31f83f1768SJoonwoo Park case ARPHRD_LOOPBACK: 32f83f1768SJoonwoo Park return sizeof(struct ethhdr); 33f83f1768SJoonwoo Park #ifdef CONFIG_TR 34f83f1768SJoonwoo Park case ARPHRD_IEEE802_TR: 35f83f1768SJoonwoo Park return sizeof(struct trh_hdr); 36f83f1768SJoonwoo Park #endif 37f83f1768SJoonwoo Park } 38f83f1768SJoonwoo Park return 0; 39f83f1768SJoonwoo Park } 40f83f1768SJoonwoo Park 411da177e4SLinus Torvalds /** 421da177e4SLinus Torvalds * llc_alloc_frame - allocates sk_buff for frame 431d67e650SArnaldo Carvalho de Melo * @dev: network device this skb will be sent over 44f83f1768SJoonwoo Park * @type: pdu type to allocate 45f83f1768SJoonwoo Park * @data_size: data size to allocate 461da177e4SLinus Torvalds * 471da177e4SLinus Torvalds * Allocates an sk_buff for frame and initializes sk_buff fields. 481da177e4SLinus Torvalds * Returns allocated skb or %NULL when out of memory. 491da177e4SLinus Torvalds */ 50f83f1768SJoonwoo Park struct sk_buff *llc_alloc_frame(struct sock *sk, struct net_device *dev, 51f83f1768SJoonwoo Park u8 type, u32 data_size) 521da177e4SLinus Torvalds { 53f83f1768SJoonwoo Park int hlen = type == LLC_PDU_TYPE_U ? 3 : 4; 54f83f1768SJoonwoo Park struct sk_buff *skb; 55f83f1768SJoonwoo Park 56f83f1768SJoonwoo Park hlen += llc_mac_header_len(dev->type); 57f83f1768SJoonwoo Park skb = alloc_skb(hlen + data_size, GFP_ATOMIC); 581da177e4SLinus Torvalds 591da177e4SLinus Torvalds if (skb) { 600a1b0ad9SArnaldo Carvalho de Melo skb_reset_mac_header(skb); 61f83f1768SJoonwoo Park skb_reserve(skb, hlen); 62c1d2bbe1SArnaldo Carvalho de Melo skb_reset_network_header(skb); 63badff6d0SArnaldo Carvalho de Melo skb_reset_transport_header(skb); 641da177e4SLinus Torvalds skb->protocol = htons(ETH_P_802_2); 651d67e650SArnaldo Carvalho de Melo skb->dev = dev; 66d389424eSArnaldo Carvalho de Melo if (sk != NULL) 67d389424eSArnaldo Carvalho de Melo skb_set_owner_w(skb, sk); 681da177e4SLinus Torvalds } 691da177e4SLinus Torvalds return skb; 701da177e4SLinus Torvalds } 711da177e4SLinus Torvalds 7204e4223fSArnaldo Carvalho de Melo void llc_save_primitive(struct sock *sk, struct sk_buff* skb, u8 prim) 731da177e4SLinus Torvalds { 748420e1b5SArnaldo Carvalho de Melo struct sockaddr_llc *addr; 751da177e4SLinus Torvalds 761da177e4SLinus Torvalds /* save primitive for use by the user. */ 778420e1b5SArnaldo Carvalho de Melo addr = llc_ui_skb_cb(skb); 7830a584d9SStephen Hemminger 7930a584d9SStephen Hemminger memset(addr, 0, sizeof(*addr)); 8004e4223fSArnaldo Carvalho de Melo addr->sllc_family = sk->sk_family; 811da177e4SLinus Torvalds addr->sllc_arphrd = skb->dev->type; 821da177e4SLinus Torvalds addr->sllc_test = prim == LLC_TEST_PRIM; 831da177e4SLinus Torvalds addr->sllc_xid = prim == LLC_XID_PRIM; 841da177e4SLinus Torvalds addr->sllc_ua = prim == LLC_DATAUNIT_PRIM; 851da177e4SLinus Torvalds llc_pdu_decode_sa(skb, addr->sllc_mac); 861da177e4SLinus Torvalds llc_pdu_decode_ssap(skb, &addr->sllc_sap); 871da177e4SLinus Torvalds } 881da177e4SLinus Torvalds 891da177e4SLinus Torvalds /** 901da177e4SLinus Torvalds * llc_sap_rtn_pdu - Informs upper layer on rx of an UI, XID or TEST pdu. 911da177e4SLinus Torvalds * @sap: pointer to SAP 921da177e4SLinus Torvalds * @skb: received pdu 931da177e4SLinus Torvalds */ 941da177e4SLinus Torvalds void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb) 951da177e4SLinus Torvalds { 961da177e4SLinus Torvalds struct llc_sap_state_ev *ev = llc_sap_ev(skb); 971da177e4SLinus Torvalds struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); 981da177e4SLinus Torvalds 991da177e4SLinus Torvalds switch (LLC_U_PDU_RSP(pdu)) { 1001da177e4SLinus Torvalds case LLC_1_PDU_CMD_TEST: 1011da177e4SLinus Torvalds ev->prim = LLC_TEST_PRIM; break; 1021da177e4SLinus Torvalds case LLC_1_PDU_CMD_XID: 1031da177e4SLinus Torvalds ev->prim = LLC_XID_PRIM; break; 1041da177e4SLinus Torvalds case LLC_1_PDU_CMD_UI: 1051da177e4SLinus Torvalds ev->prim = LLC_DATAUNIT_PRIM; break; 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds ev->ind_cfm_flag = LLC_IND; 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds /** 1111da177e4SLinus Torvalds * llc_find_sap_trans - finds transition for event 1121da177e4SLinus Torvalds * @sap: pointer to SAP 1131da177e4SLinus Torvalds * @skb: happened event 1141da177e4SLinus Torvalds * 1151da177e4SLinus Torvalds * This function finds transition that matches with happened event. 1161da177e4SLinus Torvalds * Returns the pointer to found transition on success or %NULL for 1171da177e4SLinus Torvalds * failure. 1181da177e4SLinus Torvalds */ 1191da177e4SLinus Torvalds static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap, 1201da177e4SLinus Torvalds struct sk_buff* skb) 1211da177e4SLinus Torvalds { 1221da177e4SLinus Torvalds int i = 0; 1231da177e4SLinus Torvalds struct llc_sap_state_trans *rc = NULL; 1241da177e4SLinus Torvalds struct llc_sap_state_trans **next_trans; 1251da177e4SLinus Torvalds struct llc_sap_state *curr_state = &llc_sap_state_table[sap->state - 1]; 1261da177e4SLinus Torvalds /* 1271da177e4SLinus Torvalds * Search thru events for this state until list exhausted or until 1281da177e4SLinus Torvalds * its obvious the event is not valid for the current state 1291da177e4SLinus Torvalds */ 1301da177e4SLinus Torvalds for (next_trans = curr_state->transitions; next_trans[i]->ev; i++) 1311da177e4SLinus Torvalds if (!next_trans[i]->ev(sap, skb)) { 1321da177e4SLinus Torvalds rc = next_trans[i]; /* got event match; return it */ 1331da177e4SLinus Torvalds break; 1341da177e4SLinus Torvalds } 1351da177e4SLinus Torvalds return rc; 1361da177e4SLinus Torvalds } 1371da177e4SLinus Torvalds 1381da177e4SLinus Torvalds /** 1391da177e4SLinus Torvalds * llc_exec_sap_trans_actions - execute actions related to event 1401da177e4SLinus Torvalds * @sap: pointer to SAP 1411da177e4SLinus Torvalds * @trans: pointer to transition that it's actions must be performed 1421da177e4SLinus Torvalds * @skb: happened event. 1431da177e4SLinus Torvalds * 1441da177e4SLinus Torvalds * This function executes actions that is related to happened event. 1451da177e4SLinus Torvalds * Returns 0 for success and 1 for failure of at least one action. 1461da177e4SLinus Torvalds */ 1471da177e4SLinus Torvalds static int llc_exec_sap_trans_actions(struct llc_sap *sap, 1481da177e4SLinus Torvalds struct llc_sap_state_trans *trans, 1491da177e4SLinus Torvalds struct sk_buff *skb) 1501da177e4SLinus Torvalds { 1511da177e4SLinus Torvalds int rc = 0; 1521da177e4SLinus Torvalds llc_sap_action_t *next_action = trans->ev_actions; 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds for (; next_action && *next_action; next_action++) 1551da177e4SLinus Torvalds if ((*next_action)(sap, skb)) 1561da177e4SLinus Torvalds rc = 1; 1571da177e4SLinus Torvalds return rc; 1581da177e4SLinus Torvalds } 1591da177e4SLinus Torvalds 1601da177e4SLinus Torvalds /** 1611da177e4SLinus Torvalds * llc_sap_next_state - finds transition, execs actions & change SAP state 1621da177e4SLinus Torvalds * @sap: pointer to SAP 1631da177e4SLinus Torvalds * @skb: happened event 1641da177e4SLinus Torvalds * 1651da177e4SLinus Torvalds * This function finds transition that matches with happened event, then 1661da177e4SLinus Torvalds * executes related actions and finally changes state of SAP. It returns 1671da177e4SLinus Torvalds * 0 on success and 1 for failure. 1681da177e4SLinus Torvalds */ 1691da177e4SLinus Torvalds static int llc_sap_next_state(struct llc_sap *sap, struct sk_buff *skb) 1701da177e4SLinus Torvalds { 1711da177e4SLinus Torvalds int rc = 1; 1721da177e4SLinus Torvalds struct llc_sap_state_trans *trans; 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds if (sap->state > LLC_NR_SAP_STATES) 1751da177e4SLinus Torvalds goto out; 1761da177e4SLinus Torvalds trans = llc_find_sap_trans(sap, skb); 1771da177e4SLinus Torvalds if (!trans) 1781da177e4SLinus Torvalds goto out; 1791da177e4SLinus Torvalds /* 1801da177e4SLinus Torvalds * Got the state to which we next transition; perform the actions 1811da177e4SLinus Torvalds * associated with this transition before actually transitioning to the 1821da177e4SLinus Torvalds * next state 1831da177e4SLinus Torvalds */ 1841da177e4SLinus Torvalds rc = llc_exec_sap_trans_actions(sap, trans, skb); 1851da177e4SLinus Torvalds if (rc) 1861da177e4SLinus Torvalds goto out; 1871da177e4SLinus Torvalds /* 1881da177e4SLinus Torvalds * Transition SAP to next state if all actions execute successfully 1891da177e4SLinus Torvalds */ 1901da177e4SLinus Torvalds sap->state = trans->next_state; 1911da177e4SLinus Torvalds out: 1921da177e4SLinus Torvalds return rc; 1931da177e4SLinus Torvalds } 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds /** 1961da177e4SLinus Torvalds * llc_sap_state_process - sends event to SAP state machine 1971da177e4SLinus Torvalds * @sap: sap to use 1981da177e4SLinus Torvalds * @skb: pointer to occurred event 1991da177e4SLinus Torvalds * 2001da177e4SLinus Torvalds * After executing actions of the event, upper layer will be indicated 2011da177e4SLinus Torvalds * if needed(on receiving an UI frame). sk can be null for the 2021da177e4SLinus Torvalds * datalink_proto case. 2031da177e4SLinus Torvalds */ 2041da177e4SLinus Torvalds static void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb) 2051da177e4SLinus Torvalds { 2061da177e4SLinus Torvalds struct llc_sap_state_ev *ev = llc_sap_ev(skb); 2071da177e4SLinus Torvalds 2081da177e4SLinus Torvalds /* 2091da177e4SLinus Torvalds * We have to hold the skb, because llc_sap_next_state 2101da177e4SLinus Torvalds * will kfree it in the sending path and we need to 2111da177e4SLinus Torvalds * look at the skb->cb, where we encode llc_sap_state_ev. 2121da177e4SLinus Torvalds */ 2131da177e4SLinus Torvalds skb_get(skb); 2141da177e4SLinus Torvalds ev->ind_cfm_flag = 0; 2151da177e4SLinus Torvalds llc_sap_next_state(sap, skb); 2161da177e4SLinus Torvalds if (ev->ind_cfm_flag == LLC_IND) { 2171da177e4SLinus Torvalds if (skb->sk->sk_state == TCP_LISTEN) 2181da177e4SLinus Torvalds kfree_skb(skb); 2191da177e4SLinus Torvalds else { 22004e4223fSArnaldo Carvalho de Melo llc_save_primitive(skb->sk, skb, ev->prim); 2211da177e4SLinus Torvalds 2221da177e4SLinus Torvalds /* queue skb to the user. */ 2231da177e4SLinus Torvalds if (sock_queue_rcv_skb(skb->sk, skb)) 2241da177e4SLinus Torvalds kfree_skb(skb); 2251da177e4SLinus Torvalds } 2261da177e4SLinus Torvalds } 2271da177e4SLinus Torvalds kfree_skb(skb); 2281da177e4SLinus Torvalds } 2291da177e4SLinus Torvalds 2301da177e4SLinus Torvalds /** 2311da177e4SLinus Torvalds * llc_build_and_send_test_pkt - TEST interface for upper layers. 2321da177e4SLinus Torvalds * @sap: sap to use 2331da177e4SLinus Torvalds * @skb: packet to send 2341da177e4SLinus Torvalds * @dmac: destination mac address 2351da177e4SLinus Torvalds * @dsap: destination sap 2361da177e4SLinus Torvalds * 2371da177e4SLinus Torvalds * This function is called when upper layer wants to send a TEST pdu. 2381da177e4SLinus Torvalds * Returns 0 for success, 1 otherwise. 2391da177e4SLinus Torvalds */ 2401da177e4SLinus Torvalds void llc_build_and_send_test_pkt(struct llc_sap *sap, 2411da177e4SLinus Torvalds struct sk_buff *skb, u8 *dmac, u8 dsap) 2421da177e4SLinus Torvalds { 2431da177e4SLinus Torvalds struct llc_sap_state_ev *ev = llc_sap_ev(skb); 2441da177e4SLinus Torvalds 2451da177e4SLinus Torvalds ev->saddr.lsap = sap->laddr.lsap; 2461da177e4SLinus Torvalds ev->daddr.lsap = dsap; 2471da177e4SLinus Torvalds memcpy(ev->saddr.mac, skb->dev->dev_addr, IFHWADDRLEN); 2481da177e4SLinus Torvalds memcpy(ev->daddr.mac, dmac, IFHWADDRLEN); 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds ev->type = LLC_SAP_EV_TYPE_PRIM; 2511da177e4SLinus Torvalds ev->prim = LLC_TEST_PRIM; 2521da177e4SLinus Torvalds ev->prim_type = LLC_PRIM_TYPE_REQ; 2531da177e4SLinus Torvalds llc_sap_state_process(sap, skb); 2541da177e4SLinus Torvalds } 2551da177e4SLinus Torvalds 2561da177e4SLinus Torvalds /** 2571da177e4SLinus Torvalds * llc_build_and_send_xid_pkt - XID interface for upper layers 2581da177e4SLinus Torvalds * @sap: sap to use 2591da177e4SLinus Torvalds * @skb: packet to send 2601da177e4SLinus Torvalds * @dmac: destination mac address 2611da177e4SLinus Torvalds * @dsap: destination sap 2621da177e4SLinus Torvalds * 2631da177e4SLinus Torvalds * This function is called when upper layer wants to send a XID pdu. 2641da177e4SLinus Torvalds * Returns 0 for success, 1 otherwise. 2651da177e4SLinus Torvalds */ 2661da177e4SLinus Torvalds void llc_build_and_send_xid_pkt(struct llc_sap *sap, struct sk_buff *skb, 2671da177e4SLinus Torvalds u8 *dmac, u8 dsap) 2681da177e4SLinus Torvalds { 2691da177e4SLinus Torvalds struct llc_sap_state_ev *ev = llc_sap_ev(skb); 2701da177e4SLinus Torvalds 2711da177e4SLinus Torvalds ev->saddr.lsap = sap->laddr.lsap; 2721da177e4SLinus Torvalds ev->daddr.lsap = dsap; 2731da177e4SLinus Torvalds memcpy(ev->saddr.mac, skb->dev->dev_addr, IFHWADDRLEN); 2741da177e4SLinus Torvalds memcpy(ev->daddr.mac, dmac, IFHWADDRLEN); 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds ev->type = LLC_SAP_EV_TYPE_PRIM; 2771da177e4SLinus Torvalds ev->prim = LLC_XID_PRIM; 2781da177e4SLinus Torvalds ev->prim_type = LLC_PRIM_TYPE_REQ; 2791da177e4SLinus Torvalds llc_sap_state_process(sap, skb); 2801da177e4SLinus Torvalds } 2811da177e4SLinus Torvalds 2821da177e4SLinus Torvalds /** 2831da177e4SLinus Torvalds * llc_sap_rcv - sends received pdus to the sap state machine 2841da177e4SLinus Torvalds * @sap: current sap component structure. 2851da177e4SLinus Torvalds * @skb: received frame. 2861da177e4SLinus Torvalds * 2871da177e4SLinus Torvalds * Sends received pdus to the sap state machine. 2881da177e4SLinus Torvalds */ 2893446b9d5SArnaldo Carvalho de Melo static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb, 2903446b9d5SArnaldo Carvalho de Melo struct sock *sk) 2911da177e4SLinus Torvalds { 2921da177e4SLinus Torvalds struct llc_sap_state_ev *ev = llc_sap_ev(skb); 2931da177e4SLinus Torvalds 2941da177e4SLinus Torvalds ev->type = LLC_SAP_EV_TYPE_PDU; 2951da177e4SLinus Torvalds ev->reason = 0; 2963446b9d5SArnaldo Carvalho de Melo skb->sk = sk; 2971da177e4SLinus Torvalds llc_sap_state_process(sap, skb); 2981da177e4SLinus Torvalds } 2991da177e4SLinus Torvalds 300b76f5a84SOctavian Purdila static inline bool llc_dgram_match(const struct llc_sap *sap, 301b76f5a84SOctavian Purdila const struct llc_addr *laddr, 302b76f5a84SOctavian Purdila const struct sock *sk) 303b76f5a84SOctavian Purdila { 304b76f5a84SOctavian Purdila struct llc_sock *llc = llc_sk(sk); 305b76f5a84SOctavian Purdila 306b76f5a84SOctavian Purdila return sk->sk_type == SOCK_DGRAM && 307b76f5a84SOctavian Purdila llc->laddr.lsap == laddr->lsap && 308b76f5a84SOctavian Purdila llc_mac_match(llc->laddr.mac, laddr->mac); 309b76f5a84SOctavian Purdila } 310b76f5a84SOctavian Purdila 3111da177e4SLinus Torvalds /** 3121da177e4SLinus Torvalds * llc_lookup_dgram - Finds dgram socket for the local sap/mac 3131da177e4SLinus Torvalds * @sap: SAP 3141da177e4SLinus Torvalds * @laddr: address of local LLC (MAC + SAP) 3151da177e4SLinus Torvalds * 3161da177e4SLinus Torvalds * Search socket list of the SAP and finds connection using the local 3171da177e4SLinus Torvalds * mac, and local sap. Returns pointer for socket found, %NULL otherwise. 3181da177e4SLinus Torvalds */ 3191da177e4SLinus Torvalds static struct sock *llc_lookup_dgram(struct llc_sap *sap, 320bc0e6467SStephen Hemminger const struct llc_addr *laddr) 3211da177e4SLinus Torvalds { 3221da177e4SLinus Torvalds struct sock *rc; 323b76f5a84SOctavian Purdila struct hlist_nulls_node *node; 3241da177e4SLinus Torvalds 325b76f5a84SOctavian Purdila rcu_read_lock_bh(); 326b76f5a84SOctavian Purdila again: 327b76f5a84SOctavian Purdila sk_nulls_for_each_rcu(rc, node, &sap->sk_list) { 328b76f5a84SOctavian Purdila if (llc_dgram_match(sap, laddr, rc)) { 329b76f5a84SOctavian Purdila /* Extra checks required by SLAB_DESTROY_BY_RCU */ 330b76f5a84SOctavian Purdila if (unlikely(!atomic_inc_not_zero(&rc->sk_refcnt))) 331b76f5a84SOctavian Purdila goto again; 332b76f5a84SOctavian Purdila if (unlikely(llc_sk(rc)->sap != sap || 333b76f5a84SOctavian Purdila !llc_dgram_match(sap, laddr, rc))) { 334b76f5a84SOctavian Purdila sock_put(rc); 335b76f5a84SOctavian Purdila continue; 336b76f5a84SOctavian Purdila } 3371da177e4SLinus Torvalds goto found; 3381da177e4SLinus Torvalds } 3391da177e4SLinus Torvalds } 3401da177e4SLinus Torvalds rc = NULL; 3411da177e4SLinus Torvalds found: 342b76f5a84SOctavian Purdila rcu_read_unlock_bh(); 3431da177e4SLinus Torvalds return rc; 3441da177e4SLinus Torvalds } 3451da177e4SLinus Torvalds 346b76f5a84SOctavian Purdila static inline bool llc_mcast_match(const struct llc_sap *sap, 347b76f5a84SOctavian Purdila const struct llc_addr *laddr, 348b76f5a84SOctavian Purdila const struct sk_buff *skb, 349b76f5a84SOctavian Purdila const struct sock *sk) 350b76f5a84SOctavian Purdila { 351b76f5a84SOctavian Purdila struct llc_sock *llc = llc_sk(sk); 352b76f5a84SOctavian Purdila 353b76f5a84SOctavian Purdila return sk->sk_type == SOCK_DGRAM && 354b76f5a84SOctavian Purdila llc->laddr.lsap == laddr->lsap && 355b76f5a84SOctavian Purdila llc->dev == skb->dev; 356b76f5a84SOctavian Purdila } 357b76f5a84SOctavian Purdila 358bc0e6467SStephen Hemminger /** 359bc0e6467SStephen Hemminger * llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets. 360bc0e6467SStephen Hemminger * @sap: SAP 361bc0e6467SStephen Hemminger * @laddr: address of local LLC (MAC + SAP) 362bc0e6467SStephen Hemminger * 363bc0e6467SStephen Hemminger * Search socket list of the SAP and finds connections with same sap. 364bc0e6467SStephen Hemminger * Deliver clone to each. 365bc0e6467SStephen Hemminger */ 366bc0e6467SStephen Hemminger static void llc_sap_mcast(struct llc_sap *sap, 367bc0e6467SStephen Hemminger const struct llc_addr *laddr, 368bc0e6467SStephen Hemminger struct sk_buff *skb) 369bc0e6467SStephen Hemminger { 370bc0e6467SStephen Hemminger struct sock *sk; 371b76f5a84SOctavian Purdila struct hlist_nulls_node *node; 372bc0e6467SStephen Hemminger 373b76f5a84SOctavian Purdila spin_lock_bh(&sap->sk_lock); 374b76f5a84SOctavian Purdila sk_nulls_for_each_rcu(sk, node, &sap->sk_list) { 375bc0e6467SStephen Hemminger struct sk_buff *skb1; 376bc0e6467SStephen Hemminger 377b76f5a84SOctavian Purdila if (!llc_mcast_match(sap, laddr, skb, sk)) 3787ee66fcbSStephen Hemminger continue; 3797ee66fcbSStephen Hemminger 380bc0e6467SStephen Hemminger skb1 = skb_clone(skb, GFP_ATOMIC); 381bc0e6467SStephen Hemminger if (!skb1) 382bc0e6467SStephen Hemminger break; 383bc0e6467SStephen Hemminger 384bc0e6467SStephen Hemminger sock_hold(sk); 3853446b9d5SArnaldo Carvalho de Melo llc_sap_rcv(sap, skb1, sk); 386bc0e6467SStephen Hemminger sock_put(sk); 387bc0e6467SStephen Hemminger } 388b76f5a84SOctavian Purdila spin_unlock_bh(&sap->sk_lock); 389bc0e6467SStephen Hemminger } 390bc0e6467SStephen Hemminger 391bc0e6467SStephen Hemminger 3921da177e4SLinus Torvalds void llc_sap_handler(struct llc_sap *sap, struct sk_buff *skb) 3931da177e4SLinus Torvalds { 3941da177e4SLinus Torvalds struct llc_addr laddr; 3951da177e4SLinus Torvalds 3961da177e4SLinus Torvalds llc_pdu_decode_da(skb, laddr.mac); 3971da177e4SLinus Torvalds llc_pdu_decode_dsap(skb, &laddr.lsap); 3981da177e4SLinus Torvalds 399bc0e6467SStephen Hemminger if (llc_mac_multicast(laddr.mac)) { 400bc0e6467SStephen Hemminger llc_sap_mcast(sap, &laddr, skb); 401bc0e6467SStephen Hemminger kfree_skb(skb); 402bc0e6467SStephen Hemminger } else { 403bc0e6467SStephen Hemminger struct sock *sk = llc_lookup_dgram(sap, &laddr); 4041da177e4SLinus Torvalds if (sk) { 4053446b9d5SArnaldo Carvalho de Melo llc_sap_rcv(sap, skb, sk); 4061da177e4SLinus Torvalds sock_put(sk); 4071da177e4SLinus Torvalds } else 4081da177e4SLinus Torvalds kfree_skb(skb); 4091da177e4SLinus Torvalds } 410bc0e6467SStephen Hemminger } 411