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, ...@@ -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, extern struct sock *llc_lookup_established(struct llc_sap *sap,
struct llc_addr *daddr, struct llc_addr *daddr,
struct llc_addr *laddr); 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 u8 llc_data_accept_state(u8 state);
extern void llc_build_offset_table(void); extern void llc_build_offset_table(void);
#endif /* LLC_CONN_H */ #endif /* LLC_CONN_H */
...@@ -65,24 +65,14 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb) ...@@ -65,24 +65,14 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb)
sap = llc_sap_find(dsap); sap = llc_sap_find(dsap);
if (sap) { if (sap) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); 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); struct llc_opt *llc = llc_sk(sk);
prim_data->conn.daddr.lsap = dsap;
llc_pdu_decode_sa(skb, llc->daddr.mac); llc_pdu_decode_sa(skb, llc->daddr.mac);
llc_pdu_decode_da(skb, llc->laddr.mac); llc_pdu_decode_da(skb, llc->laddr.mac);
llc->dev = skb->dev; llc->dev = skb->dev;
prim_data->conn.pri = 0; /* FIXME: find better way to notify upper layer */
prim_data->conn.sk = sk; ev->flag = LLC_CONN_PRIM + 1;
prim_data->conn.dev = skb->dev; ev->ind_prim = (void *)1;
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;
rc = 0; rc = 0;
} }
return rc; return rc;
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <net/llc_sap.h> #include <net/llc_sap.h>
#include <net/llc_conn.h> #include <net/llc_conn.h>
#include <net/sock.h> #include <net/sock.h>
#include <linux/tcp.h>
#include <net/llc_main.h> #include <net/llc_main.h>
#include <net/llc_c_ev.h> #include <net/llc_c_ev.h>
#include <net/llc_c_ac.h> #include <net/llc_c_ac.h>
...@@ -61,7 +62,7 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) ...@@ -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 * 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); llc_conn_free_ev(skb);
else if (ind_prim && cfm_prim) else if (ind_prim && cfm_prim)
skb_get(skb); skb_get(skb);
...@@ -73,7 +74,8 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *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 * FIXME: this will be saner as soon I get rid of the double
* sock crap * sock crap
*/ */
if (flag == LLC_DATA_PRIM + 1) { switch (flag) {
case LLC_DATA_PRIM + 1:
if (sock_queue_rcv_skb(skb->sk, skb)) { if (sock_queue_rcv_skb(skb->sk, skb)) {
/* /*
* FIXME: have to sync the LLC state * FIXME: have to sync the LLC state
...@@ -86,9 +88,19 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) ...@@ -86,9 +88,19 @@ int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
__FUNCTION__); __FUNCTION__);
kfree_skb(skb); 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); llc->sap->ind(ind_prim);
} }
}
if (!cfm_prim) /* confirmation not required */ if (!cfm_prim) /* confirmation not required */
goto out; goto out;
/* data confirm has preconditions */ /* data confirm has preconditions */
...@@ -433,6 +445,39 @@ struct sock *llc_lookup_established(struct llc_sap *sap, struct llc_addr *daddr, ...@@ -433,6 +445,39 @@ struct sock *llc_lookup_established(struct llc_sap *sap, struct llc_addr *daddr,
return rc; 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. * llc_data_accept_state - designates if in this state data can be sent.
* @state: state of connection. * @state: state of connection.
......
...@@ -123,23 +123,33 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -123,23 +123,33 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
sk = llc_lookup_established(sap, &saddr, &daddr); sk = llc_lookup_established(sap, &saddr, &daddr);
if (!sk) { if (!sk) {
struct llc_opt *llc;
dprintk("%s: llc_lookup_established failed\n", __FUNCTION__);
/* /*
* FIXME: here we'll pass the sk->family of the * Didn't find an active connection; verify if there
* listening socket, if found, when * is a listening socket for this llc addr
* llc_lookup_listener is added in the next patches.
*/ */
sk = llc_sk_alloc(PF_LLC, GFP_ATOMIC); struct llc_opt *llc;
if (!sk) struct sock *parent;
parent = llc_lookup_listener(sap, &daddr);
if (!parent) {
dprintk("llc_lookup_listener failed!\n");
goto drop; goto drop;
}
sk = llc_sk_alloc(parent->family, GFP_ATOMIC);
if (!sk) {
sock_put(parent);
goto drop;
}
llc = llc_sk(sk); llc = llc_sk(sk);
memcpy(&llc->laddr, &daddr, sizeof(llc->laddr)); memcpy(&llc->laddr, &daddr, sizeof(llc->laddr));
memcpy(&llc->daddr, &saddr, sizeof(llc->daddr)); memcpy(&llc->daddr, &saddr, sizeof(llc->daddr));
llc_sap_assign_sock(sap, sk); llc_sap_assign_sock(sap, sk);
sock_hold(sk); sock_hold(sk);
} sock_put(parent);
skb->sk = parent;
} else
skb->sk = sk; skb->sk = sk;
bh_lock_sock(sk); bh_lock_sock(sk);
if (!sk->lock.users) { if (!sk->lock.users) {
......
...@@ -923,6 +923,7 @@ static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags) ...@@ -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, &llc->addr, sizeof(newllc->addr));
memcpy(newllc->addr.sllc_dmac, newllc->daddr.mac, IFHWADDRLEN); memcpy(newllc->addr.sllc_dmac, newllc->daddr.mac, IFHWADDRLEN);
newllc->addr.sllc_dsap = newllc->daddr.lsap; 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. */ /* put original socket back into a clean listen state. */
sk->state = TCP_LISTEN; sk->state = TCP_LISTEN;
...@@ -1378,48 +1379,6 @@ static void llc_ui_ind_dataunit(struct llc_prim_if_block *prim) ...@@ -1378,48 +1379,6 @@ static void llc_ui_ind_dataunit(struct llc_prim_if_block *prim)
out:; 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 * llc_ui_ind_disc - handle DISC indication
* @prim: Primitive block provided by the llc layer. * @prim: Primitive block provided by the llc layer.
...@@ -1465,7 +1424,9 @@ static int llc_ui_indicate(struct llc_prim_if_block *prim) ...@@ -1465,7 +1424,9 @@ static int llc_ui_indicate(struct llc_prim_if_block *prim)
case LLC_DATAUNIT_PRIM: case LLC_DATAUNIT_PRIM:
llc_ui_ind_dataunit(prim); break; llc_ui_ind_dataunit(prim); break;
case LLC_CONN_PRIM: 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: case LLC_DATA_PRIM:
dprintk("%s: shouldn't happen, LLC_DATA_PRIM " dprintk("%s: shouldn't happen, LLC_DATA_PRIM "
"is gone for ->ind()...\n", __FUNCTION__); "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