LLC: llc_lookup_listener

With this LLC_CONN_PRIM and friends went to the death row, next
patch will introduce llc_establish_connection, turning on the
electric chair switch for LLC_CONN_PRIM et al.
parent 269f04b7
......@@ -99,6 +99,8 @@ extern int llc_conn_remove_acked_pdus(struct sock *conn, u8 nr,
extern struct sock *llc_lookup_established(struct llc_sap *sap,
struct llc_addr *daddr,
struct llc_addr *laddr);
extern struct sock *llc_lookup_listener(struct llc_sap *sap,
struct llc_addr *laddr);
extern u8 llc_data_accept_state(u8 state);
extern void llc_build_offset_table(void);
#endif /* LLC_CONN_H */
......@@ -65,24 +65,14 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb)
sap = llc_sap_find(dsap);
if (sap) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb);
struct llc_prim_if_block *prim = &sap->llc_ind_prim;
union llc_u_prim_data *prim_data = prim->data;
struct llc_opt *llc = llc_sk(sk);
prim_data->conn.daddr.lsap = dsap;
llc_pdu_decode_sa(skb, llc->daddr.mac);
llc_pdu_decode_da(skb, llc->laddr.mac);
llc->dev = skb->dev;
prim_data->conn.pri = 0;
prim_data->conn.sk = sk;
prim_data->conn.dev = skb->dev;
memcpy(&prim_data->conn.daddr, &llc->laddr, sizeof(llc->laddr));
memcpy(&prim_data->conn.saddr, &llc->daddr, sizeof(llc->daddr));
prim->data = prim_data;
prim->prim = LLC_CONN_PRIM;
prim->sap = llc->sap;
ev->flag = 1;
ev->ind_prim = prim;
/* FIXME: find better way to notify upper layer */
ev->flag = LLC_CONN_PRIM + 1;
ev->ind_prim = (void *)1;
rc = 0;
}
return rc;
......
......@@ -18,6 +18,7 @@
#include <net/llc_sap.h>
#include <net/llc_conn.h>
#include <net/sock.h>
#include <linux/tcp.h>
#include <net/llc_main.h>
#include <net/llc_c_ev.h>
#include <net/llc_c_ac.h>
......@@ -61,7 +62,7 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
/*
* FIXME: this will vanish as soon I get rid of the double sock crap
*/
if (flag != LLC_DATA_PRIM + 1)
if (flag != LLC_DATA_PRIM + 1 && flag != LLC_CONN_PRIM + 1)
llc_conn_free_ev(skb);
else if (ind_prim && cfm_prim)
skb_get(skb);
......@@ -73,7 +74,8 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
* FIXME: this will be saner as soon I get rid of the double
* sock crap
*/
if (flag == LLC_DATA_PRIM + 1) {
switch (flag) {
case LLC_DATA_PRIM + 1:
if (sock_queue_rcv_skb(skb->sk, skb)) {
/*
* FIXME: have to sync the LLC state
......@@ -86,9 +88,19 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
__FUNCTION__);
kfree_skb(skb);
}
} else
break;
case LLC_CONN_PRIM + 1: {
struct sock *parent = skb->sk;
skb->sk = sk;
skb_queue_tail(&parent->receive_queue, skb);
sk->state_change(parent);
}
break;
default:
llc->sap->ind(ind_prim);
}
}
if (!cfm_prim) /* confirmation not required */
goto out;
/* data confirm has preconditions */
......@@ -433,6 +445,39 @@ struct sock *llc_lookup_established(struct llc_sap *sap, struct llc_addr *daddr,
return rc;
}
/**
* llc_lookup_listener - Finds listener for local MAC + SAP
* @sap: SAP
* @laddr: address of local LLC (MAC + SAP)
*
* Search connection list of the SAP and finds connection listening on
* local mac, and local sap. Returns pointer for parent socket found,
* %NULL otherwise.
*/
struct sock *llc_lookup_listener(struct llc_sap *sap, struct llc_addr *laddr)
{
struct sock *rc = NULL;
struct list_head *entry;
spin_lock_bh(&sap->sk_list.lock);
if (list_empty(&sap->sk_list.list))
goto out;
list_for_each(entry, &sap->sk_list.list) {
struct llc_opt *llc = list_entry(entry, struct llc_opt, node);
if (llc->sk->type != SOCK_STREAM || llc->sk->state != TCP_LISTEN ||
llc->laddr.lsap != laddr->lsap ||
!llc_mac_match(llc->laddr.mac, laddr->mac))
continue;
rc = llc->sk;
}
if (rc)
sock_hold(rc);
out:
spin_unlock_bh(&sap->sk_list.lock);
return rc;
}
/**
* llc_data_accept_state - designates if in this state data can be sent.
* @state: state of connection.
......
......@@ -123,23 +123,33 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
sk = llc_lookup_established(sap, &saddr, &daddr);
if (!sk) {
struct llc_opt *llc;
dprintk("%s: llc_lookup_established failed\n", __FUNCTION__);
/*
* FIXME: here we'll pass the sk->family of the
* listening socket, if found, when
* llc_lookup_listener is added in the next patches.
* Didn't find an active connection; verify if there
* is a listening socket for this llc addr
*/
sk = llc_sk_alloc(PF_LLC, GFP_ATOMIC);
if (!sk)
struct llc_opt *llc;
struct sock *parent;
parent = llc_lookup_listener(sap, &daddr);
if (!parent) {
dprintk("llc_lookup_listener failed!\n");
goto drop;
}
sk = llc_sk_alloc(parent->family, GFP_ATOMIC);
if (!sk) {
sock_put(parent);
goto drop;
}
llc = llc_sk(sk);
memcpy(&llc->laddr, &daddr, sizeof(llc->laddr));
memcpy(&llc->daddr, &saddr, sizeof(llc->daddr));
llc_sap_assign_sock(sap, sk);
sock_hold(sk);
}
sock_put(parent);
skb->sk = parent;
} else
skb->sk = sk;
bh_lock_sock(sk);
if (!sk->lock.users) {
......
......@@ -923,6 +923,7 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags)
memcpy(&newllc->addr, &llc->addr, sizeof(newllc->addr));
memcpy(newllc->addr.sllc_dmac, newllc->daddr.mac, IFHWADDRLEN);
newllc->addr.sllc_dsap = newllc->daddr.lsap;
newllc->link = llc_ui_next_link_no(newllc->laddr.lsap);
/* put original socket back into a clean listen state. */
sk->state = TCP_LISTEN;
......@@ -1378,48 +1379,6 @@ static void llc_ui_ind_dataunit(struct llc_prim_if_block *prim)
out:;
}
/**
* llc_ui_ind_conn - handle CONNECT indication
* @prim: Primitive block provided by the llc layer.
*
* handle CONNECT indication.
*/
static void llc_ui_ind_conn(struct llc_prim_if_block *prim)
{
struct llc_prim_conn *prim_data = &prim->data->conn;
struct sock* newsk = prim_data->sk, *parent;
struct llc_opt *newllc = llc_sk(newsk);
struct sk_buff *skb2;
parent = llc_ui_find_sk_by_addr(&newllc->laddr, &prim_data->saddr,
prim_data->dev);
if (!parent) {
dprintk("%s: can't find a parent :-(\n", __FUNCTION__);
goto out;
}
dprintk("%s: found parent of remote %02X, its local %02X\n", __FUNCTION__,
newllc->daddr.lsap, llc_sk(parent)->laddr.lsap);
if (parent->type != SOCK_STREAM || parent->state != TCP_LISTEN) {
dprintk("%s: bad parent :-(\n", __FUNCTION__);
goto out_put;
}
if (prim->data->conn.status) {
dprintk("%s: bad status :-(\n", __FUNCTION__);
goto out_put; /* bad status. */
}
/* give this connection a link number. */
newllc->link = llc_ui_next_link_no(newllc->laddr.lsap);
skb2 = alloc_skb(0, GFP_ATOMIC);
if (!skb2)
goto out_put;
skb2->sk = newsk;
skb_queue_tail(&parent->receive_queue, skb2);
parent->state_change(parent);
out_put:
sock_put(parent);
out:;
}
/**
* llc_ui_ind_disc - handle DISC indication
* @prim: Primitive block provided by the llc layer.
......@@ -1465,7 +1424,9 @@ static int llc_ui_indicate(struct llc_prim_if_block *prim)
case LLC_DATAUNIT_PRIM:
llc_ui_ind_dataunit(prim); break;
case LLC_CONN_PRIM:
llc_ui_ind_conn(prim); break;
dprintk("%s: shouldn't happen, LLC_CONN_PRIM "
"is gone for ->ind()...\n", __FUNCTION__);
break;
case LLC_DATA_PRIM:
dprintk("%s: shouldn't happen, LLC_DATA_PRIM "
"is gone for ->ind()...\n", __FUNCTION__);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment