summaryrefslogtreecommitdiffstats
path: root/net/llc
diff options
context:
space:
mode:
Diffstat (limited to 'net/llc')
-rw-r--r--net/llc/af_llc.c6
-rw-r--r--net/llc/llc_if.c2
-rw-r--r--net/llc/llc_input.c10
-rw-r--r--net/llc/llc_sap.c59
4 files changed, 61 insertions, 16 deletions
diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c
index 5a04db745c8d..75c9b1480801 100644
--- a/net/llc/af_llc.c
+++ b/net/llc/af_llc.c
@@ -674,7 +674,7 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock,
lock_sock(sk);
copied = -ENOTCONN;
- if (sk->sk_state == TCP_LISTEN)
+ if (unlikely(sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_LISTEN))
goto out;
timeo = sock_rcvtimeo(sk, nonblock);
@@ -733,7 +733,7 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock,
if (sk->sk_shutdown & RCV_SHUTDOWN)
break;
- if (sk->sk_state == TCP_CLOSE) {
+ if (sk->sk_type == SOCK_STREAM && sk->sk_state == TCP_CLOSE) {
if (!sock_flag(sk, SOCK_DONE)) {
/*
* This occurs when user tries to read
@@ -789,7 +789,7 @@ static int llc_ui_recvmsg(struct kiocb *iocb, struct socket *sock,
continue;
if (!(flags & MSG_PEEK)) {
- sk_eat_skb(sk, skb);
+ sk_eat_skb(sk, skb, 0);
*seq = 0;
}
} while (len > 0);
diff --git a/net/llc/llc_if.c b/net/llc/llc_if.c
index ba90f7f0801a..5ae47be7dde0 100644
--- a/net/llc/llc_if.c
+++ b/net/llc/llc_if.c
@@ -26,8 +26,6 @@
#include <net/llc_c_st.h>
#include <net/tcp_states.h>
-u8 llc_mac_null_var[IFHWADDRLEN];
-
/**
* llc_build_and_send_pkt - Connection data sending for upper layers.
* @sk: connection
diff --git a/net/llc/llc_input.c b/net/llc/llc_input.c
index d62e0f9b9da3..94d2368ade92 100644
--- a/net/llc/llc_input.c
+++ b/net/llc/llc_input.c
@@ -142,6 +142,8 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
struct llc_sap *sap;
struct llc_pdu_sn *pdu;
int dest;
+ int (*rcv)(struct sk_buff *, struct net_device *,
+ struct packet_type *, struct net_device *);
/*
* When the interface is in promisc. mode, drop all the crap that it
@@ -169,9 +171,11 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
* First the upper layer protocols that don't need the full
* LLC functionality
*/
- if (sap->rcv_func) {
- sap->rcv_func(skb, dev, pt, orig_dev);
- goto out_put;
+ rcv = rcu_dereference(sap->rcv_func);
+ if (rcv) {
+ struct sk_buff *cskb = skb_clone(skb, GFP_ATOMIC);
+ if (cskb)
+ rcv(cskb, dev, pt, orig_dev);
}
dest = llc_pdu_type(skb);
if (unlikely(!dest || !llc_type_handlers[dest - 1]))
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)
* mac, and local sap. Returns pointer for socket found, %NULL otherwise.
*/
static struct sock *llc_lookup_dgram(struct llc_sap *sap,
- struct llc_addr *laddr)
+ const struct llc_addr *laddr)
{
struct sock *rc;
struct hlist_node *node;
@@ -304,19 +304,62 @@ found:
return rc;
}
+/**
+ * llc_sap_mcast - Deliver multicast PDU's to all matching datagram sockets.
+ * @sap: SAP
+ * @laddr: address of local LLC (MAC + SAP)
+ *
+ * Search socket list of the SAP and finds connections with same sap.
+ * Deliver clone to each.
+ */
+static void llc_sap_mcast(struct llc_sap *sap,
+ const struct llc_addr *laddr,
+ struct sk_buff *skb)
+{
+ struct sock *sk;
+ struct hlist_node *node;
+
+ read_lock_bh(&sap->sk_list.lock);
+ sk_for_each(sk, node, &sap->sk_list.list) {
+ struct llc_sock *llc = llc_sk(sk);
+ struct sk_buff *skb1;
+
+ if (sk->sk_type != SOCK_DGRAM)
+ continue;
+
+ if (llc->laddr.lsap != laddr->lsap)
+ continue;
+
+ skb1 = skb_clone(skb, GFP_ATOMIC);
+ if (!skb1)
+ break;
+
+ sock_hold(sk);
+ skb_set_owner_r(skb1, sk);
+ llc_sap_rcv(sap, skb1);
+ sock_put(sk);
+ }
+ read_unlock_bh(&sap->sk_list.lock);
+}
+
+
void llc_sap_handler(struct llc_sap *sap, struct sk_buff *skb)
{
struct llc_addr laddr;
- struct sock *sk;
llc_pdu_decode_da(skb, laddr.mac);
llc_pdu_decode_dsap(skb, &laddr.lsap);
- sk = llc_lookup_dgram(sap, &laddr);
- if (sk) {
- skb_set_owner_r(skb, sk);
- llc_sap_rcv(sap, skb);
- sock_put(sk);
- } else
+ if (llc_mac_multicast(laddr.mac)) {
+ llc_sap_mcast(sap, &laddr, skb);
kfree_skb(skb);
+ } else {
+ struct sock *sk = llc_lookup_dgram(sap, &laddr);
+ if (sk) {
+ skb_set_owner_r(skb, sk);
+ llc_sap_rcv(sap, skb);
+ sock_put(sk);
+ } else
+ kfree_skb(skb);
+ }
}