Commit 71d24cc6 authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo Committed by David S. Miller

[LLC] kill sap->{ind,conf}, finally!

With this one the sap->ind and ->conf callbacks are gone, now the core
is tightly integrated with the socket layer (PF_LLC) and the
datalink_protos are mostly working like when the old LLC stack was
in the kernel, i.e. without special receiving routines for IPX in
802.2 mode, now I have to work on the UI sending routines to kill more
stupid structs. 
parent 1502caff
...@@ -138,9 +138,8 @@ struct llc_conn_state_ev { ...@@ -138,9 +138,8 @@ struct llc_conn_state_ev {
u8 type; u8 type;
u8 reason; u8 reason;
u8 status; u8 status;
u8 flag; u8 ind_prim;
struct llc_prim_if_block *ind_prim; u8 cfm_prim;
struct llc_prim_if_block *cfm_prim;
union llc_conn_ev_if data; union llc_conn_ev_if data;
}; };
......
...@@ -100,6 +100,9 @@ extern struct sock *llc_lookup_established(struct llc_sap *sap, ...@@ -100,6 +100,9 @@ extern struct sock *llc_lookup_established(struct llc_sap *sap,
struct llc_addr *laddr); struct llc_addr *laddr);
extern struct sock *llc_lookup_listener(struct llc_sap *sap, extern struct sock *llc_lookup_listener(struct llc_sap *sap,
struct llc_addr *laddr); struct llc_addr *laddr);
extern struct sock *llc_lookup_dgram(struct llc_sap *sap,
struct llc_addr *laddr);
extern void llc_save_primitive(struct sk_buff* skb, u8 prim);
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 */
...@@ -17,17 +17,17 @@ ...@@ -17,17 +17,17 @@
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/llc.h> #include <linux/llc.h>
#define LLC_DATAUNIT_PRIM 0 #define LLC_DATAUNIT_PRIM 1
#define LLC_CONN_PRIM 1 #define LLC_CONN_PRIM 2
#define LLC_DATA_PRIM 2 #define LLC_DATA_PRIM 3
#define LLC_DISC_PRIM 3 #define LLC_DISC_PRIM 4
#define LLC_RESET_PRIM 4 #define LLC_RESET_PRIM 5
#define LLC_FLOWCONTROL_PRIM 5 /* Not supported at this time */ #define LLC_FLOWCONTROL_PRIM 6 /* Not supported at this time */
#define LLC_DISABLE_PRIM 6 #define LLC_DISABLE_PRIM 7
#define LLC_XID_PRIM 7 #define LLC_XID_PRIM 8
#define LLC_TEST_PRIM 8 #define LLC_TEST_PRIM 9
#define LLC_SAP_ACTIVATION 9 #define LLC_SAP_ACTIVATION 10
#define LLC_SAP_DEACTIVATION 10 #define LLC_SAP_DEACTIVATION 11
#define LLC_NBR_PRIMITIVES 11 #define LLC_NBR_PRIMITIVES 11
...@@ -110,23 +110,21 @@ struct llc_prim_if_block { ...@@ -110,23 +110,21 @@ struct llc_prim_if_block {
u8 prim; u8 prim;
union llc_u_prim_data *data; union llc_u_prim_data *data;
}; };
typedef int (*llc_prim_call_t)(struct llc_prim_if_block *prim_if);
extern struct llc_sap *llc_sap_open(llc_prim_call_t network_indicate, extern struct llc_sap *llc_sap_open(u8 lsap,
llc_prim_call_t network_confirm, u8 lsap); int (*func)(struct sk_buff *skb,
struct net_device *dev,
struct packet_type *pt));
extern void llc_sap_close(struct llc_sap *sap); extern void llc_sap_close(struct llc_sap *sap);
extern int llc_establish_connection(struct sock *sk, u8 *lmac, extern int llc_establish_connection(struct sock *sk, u8 *lmac,
u8 *dmac, u8 dsap); u8 *dmac, u8 dsap);
extern int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb); extern int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb);
extern void llc_build_and_send_ui_pkt(struct llc_sap *sap, extern void llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb,
struct sk_buff *skb,
u8 *dmac, u8 dsap); u8 *dmac, u8 dsap);
extern void llc_build_and_send_xid_pkt(struct llc_sap *sap, extern void llc_build_and_send_xid_pkt(struct llc_sap *sap, struct sk_buff *skb,
struct sk_buff *skb,
u8 *dmac, u8 dsap); u8 *dmac, u8 dsap);
extern void llc_build_and_send_test_pkt(struct llc_sap *sap, extern void llc_build_and_send_test_pkt(struct llc_sap *sap, struct sk_buff *skb,
struct sk_buff *skb,
u8 *dmac, u8 dsap); u8 *dmac, u8 dsap);
extern int llc_send_disc(struct sock *sk); extern int llc_send_disc(struct sock *sk);
#endif /* LLC_IF_H */ #endif /* LLC_IF_H */
...@@ -64,4 +64,5 @@ extern void llc_station_state_process(struct llc_station *station, ...@@ -64,4 +64,5 @@ extern void llc_station_state_process(struct llc_station *station,
extern void llc_station_send_pdu(struct llc_station *station, extern void llc_station_send_pdu(struct llc_station *station,
struct sk_buff *skb); struct sk_buff *skb);
extern struct sk_buff *llc_alloc_frame(void); extern struct sk_buff *llc_alloc_frame(void);
extern struct packet_type llc_packet_type;
#endif /* LLC_MAIN_H */ #endif /* LLC_MAIN_H */
...@@ -60,6 +60,7 @@ union llc_sap_ev_if { ...@@ -60,6 +60,7 @@ union llc_sap_ev_if {
struct llc_prim_if_block; struct llc_prim_if_block;
struct llc_sap_state_ev { struct llc_sap_state_ev {
u8 primitive;
u8 type; u8 type;
u8 reason; u8 reason;
u8 ind_cfm_flag; u8 ind_cfm_flag;
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*/ */
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <net/llc_if.h>
/** /**
* struct llc_sap - Defines the SAP component * struct llc_sap - Defines the SAP component
* *
...@@ -29,10 +30,9 @@ struct llc_sap { ...@@ -29,10 +30,9 @@ struct llc_sap {
u8 state; u8 state;
u8 p_bit; u8 p_bit;
u8 f_bit; u8 f_bit;
llc_prim_call_t ind; int (*rcv_func)(struct sk_buff *skb,
llc_prim_call_t conf; struct net_device *dev,
struct llc_prim_if_block llc_ind_prim, llc_cfm_prim; struct packet_type *pt);
union llc_u_prim_data llc_ind_data_prim, llc_cfm_data_prim;
struct llc_addr laddr; struct llc_addr laddr;
struct list_head node; struct list_head node;
struct { struct {
...@@ -45,7 +45,8 @@ struct llc_sap_state_ev; ...@@ -45,7 +45,8 @@ struct llc_sap_state_ev;
extern void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk); extern void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk);
extern void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk); extern void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk);
extern void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb); extern void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb,
struct packet_type *pt);
extern void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb); extern void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb);
extern void llc_sap_send_pdu(struct llc_sap *sap, struct sk_buff *skb); extern void llc_sap_send_pdu(struct llc_sap *sap, struct sk_buff *skb);
#endif /* LLC_SAP_H */ #endif /* LLC_SAP_H */
#ifndef _NET_P8022_H #ifndef _NET_P8022_H
#define _NET_P8022_H #define _NET_P8022_H
#include <net/llc_if.h> extern struct datalink_proto *
register_8022_client(unsigned char type,
extern struct datalink_proto *register_8022_client(unsigned char type, int (*func)(struct sk_buff *skb,
int (*indicate)(struct llc_prim_if_block *prim)); struct net_device *dev,
struct packet_type *pt));
extern void unregister_8022_client(struct datalink_proto *proto); extern void unregister_8022_client(struct datalink_proto *proto);
#endif #endif
...@@ -33,7 +33,9 @@ static int p8022_request(struct datalink_proto *dl, struct sk_buff *skb, ...@@ -33,7 +33,9 @@ static int p8022_request(struct datalink_proto *dl, struct sk_buff *skb,
} }
struct datalink_proto *register_8022_client(unsigned char type, struct datalink_proto *register_8022_client(unsigned char type,
int (*indicate)(struct llc_prim_if_block *prim)) int (*func)(struct sk_buff *skb,
struct net_device *dev,
struct packet_type *pt))
{ {
struct datalink_proto *proto; struct datalink_proto *proto;
...@@ -42,7 +44,7 @@ struct datalink_proto *register_8022_client(unsigned char type, ...@@ -42,7 +44,7 @@ struct datalink_proto *register_8022_client(unsigned char type,
proto->type[0] = type; proto->type[0] = type;
proto->header_length = 3; proto->header_length = 3;
proto->request = p8022_request; proto->request = p8022_request;
proto->sap = llc_sap_open(indicate, NULL, type); proto->sap = llc_sap_open(type, func);
if (!proto->sap) { if (!proto->sap) {
kfree(proto); kfree(proto);
proto = NULL; proto = NULL;
......
...@@ -51,32 +51,23 @@ static struct datalink_proto *find_snap_client(unsigned char *desc) ...@@ -51,32 +51,23 @@ static struct datalink_proto *find_snap_client(unsigned char *desc)
/* /*
* A SNAP packet has arrived * A SNAP packet has arrived
*/ */
static int snap_indicate(struct llc_prim_if_block *prim) static int snap_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt)
{ {
struct sk_buff *skb;
struct datalink_proto *proto;
int rc = 1; int rc = 1;
static struct packet_type psnap_packet_type = { struct datalink_proto *proto = find_snap_client(skb->h.raw);
.type = __constant_htons(ETH_P_SNAP),
};
if (prim->prim != LLC_DATAUNIT_PRIM)
goto out;
skb = prim->data->udata.skb;
proto = find_snap_client(skb->h.raw);
if (proto) { if (proto) {
/* Pass the frame on. */ /* Pass the frame on. */
skb->h.raw += 5; skb->h.raw += 5;
skb_pull(skb, 5); skb_pull(skb, 5);
rc = proto->rcvfunc(skb, skb->dev, &psnap_packet_type); rc = proto->rcvfunc(skb, dev, pt);
} else { } else {
skb->sk = NULL; skb->sk = NULL;
kfree_skb(skb); kfree_skb(skb);
rc = 1; rc = 1;
} }
out:
return rc; return rc;
} }
...@@ -99,7 +90,7 @@ EXPORT_SYMBOL(unregister_snap_client); ...@@ -99,7 +90,7 @@ EXPORT_SYMBOL(unregister_snap_client);
static int __init snap_init(void) static int __init snap_init(void)
{ {
snap_sap = llc_sap_open(snap_indicate, NULL, 0xAA); snap_sap = llc_sap_open(0xAA, snap_rcv);
if (!snap_sap) if (!snap_sap)
printk(KERN_CRIT "SNAP - unable to register with 802.2\n"); printk(KERN_CRIT "SNAP - unable to register with 802.2\n");
......
...@@ -2252,22 +2252,6 @@ drop: kfree_skb(skb); ...@@ -2252,22 +2252,6 @@ drop: kfree_skb(skb);
out: return ret; out: return ret;
} }
static int ipx_8022_indicate(struct llc_prim_if_block *prim)
{
int rc = 1;
static struct packet_type p8022_packet_type = {
.type = __constant_htons(ETH_P_802_2),
};
if (prim->prim == LLC_DATAUNIT_PRIM) {
struct sk_buff *skb = prim->data->udata.skb;
rc = ipx_rcv(skb, skb->dev, &p8022_packet_type);
}
return rc;
}
static int ipx_sendmsg(struct socket *sock, struct msghdr *msg, int len, static int ipx_sendmsg(struct socket *sock, struct msghdr *msg, int len,
struct scm_cookie *scm) struct scm_cookie *scm)
{ {
...@@ -2560,7 +2544,7 @@ static int __init ipx_init(void) ...@@ -2560,7 +2544,7 @@ static int __init ipx_init(void)
else else
printk(ipx_8023_err_msg); printk(ipx_8023_err_msg);
p8022_datalink = register_8022_client(ipx_8022_type, ipx_8022_indicate); p8022_datalink = register_8022_client(ipx_8022_type, ipx_rcv);
if (!p8022_datalink) if (!p8022_datalink)
printk(ipx_llc_err_msg); printk(ipx_llc_err_msg);
......
...@@ -65,9 +65,7 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb) ...@@ -65,9 +65,7 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb)
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;
/* FIXME: find better way to notify upper layer */ ev->ind_prim = LLC_CONN_PRIM;
ev->flag = LLC_CONN_PRIM + 1;
ev->ind_prim = (void *)1;
rc = 0; rc = 0;
} }
return rc; return rc;
...@@ -77,8 +75,7 @@ int llc_conn_ac_conn_confirm(struct sock *sk, struct sk_buff *skb) ...@@ -77,8 +75,7 @@ int llc_conn_ac_conn_confirm(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
ev->flag = LLC_CONN_PRIM + 1; ev->cfm_prim = LLC_CONN_PRIM;
ev->cfm_prim = (void *)1;
return 0; return 0;
} }
...@@ -86,12 +83,7 @@ static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *skb) ...@@ -86,12 +83,7 @@ static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
/* ev->cfm_prim = LLC_DATA_PRIM;
* FIXME: find better way to tell upper layer that the packet was
* confirmed by the other endpoint
*/
ev->flag = LLC_DATA_PRIM + 1;
ev->cfm_prim = (void *)1;
return 0; return 0;
} }
...@@ -130,8 +122,7 @@ int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb) ...@@ -130,8 +122,7 @@ int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb)
} }
if (!rc) { if (!rc) {
ev->reason = reason; ev->reason = reason;
ev->flag = LLC_DISC_PRIM + 1; ev->ind_prim = LLC_DISC_PRIM;
ev->ind_prim = (void *)1;
} }
return rc; return rc;
} }
...@@ -141,8 +132,7 @@ int llc_conn_ac_disc_confirm(struct sock *sk, struct sk_buff *skb) ...@@ -141,8 +132,7 @@ int llc_conn_ac_disc_confirm(struct sock *sk, struct sk_buff *skb)
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
ev->reason = ev->status; ev->reason = ev->status;
ev->flag = LLC_DISC_PRIM + 1; ev->cfm_prim = LLC_DISC_PRIM;
ev->cfm_prim = (void *)1;
return 0; return 0;
} }
...@@ -184,18 +174,8 @@ int llc_conn_ac_rst_ind(struct sock *sk, struct sk_buff *skb) ...@@ -184,18 +174,8 @@ int llc_conn_ac_rst_ind(struct sock *sk, struct sk_buff *skb)
break; break;
} }
if (!rc) { if (!rc) {
struct llc_sap *sap = llc->sap; ev->reason = reason;
struct llc_prim_if_block *prim = &sap->llc_ind_prim; ev->ind_prim = LLC_RESET_PRIM;
union llc_u_prim_data *prim_data = prim->data;
prim_data->res.sk = sk;
prim_data->res.link = llc->link;
prim->data = prim_data;
prim->prim = LLC_RESET_PRIM;
prim->sap = sap;
ev->reason = reason;
ev->flag = 1;
ev->ind_prim = prim;
} }
return rc; return rc;
} }
...@@ -203,18 +183,9 @@ int llc_conn_ac_rst_ind(struct sock *sk, struct sk_buff *skb) ...@@ -203,18 +183,9 @@ int llc_conn_ac_rst_ind(struct sock *sk, struct sk_buff *skb)
int llc_conn_ac_rst_confirm(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_rst_confirm(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap; ev->reason = 0;
struct llc_prim_if_block *prim = &sap->llc_cfm_prim; ev->cfm_prim = LLC_RESET_PRIM;
union llc_u_prim_data *prim_data = prim->data;
prim_data->res.sk = sk;
prim_data->res.link = llc->link;
prim->data = prim_data;
prim->prim = LLC_RESET_PRIM;
prim->sap = sap;
ev->flag = 1;
ev->cfm_prim = prim;
return 0; return 0;
} }
......
...@@ -39,12 +39,12 @@ static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk, ...@@ -39,12 +39,12 @@ static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk,
/* Offset table on connection states transition diagram */ /* Offset table on connection states transition diagram */
static int llc_offset_table[NBR_CONN_STATES][NBR_CONN_EV]; static int llc_offset_table[NBR_CONN_STATES][NBR_CONN_EV];
void llc_save_primitive(struct sock *sk, struct sk_buff* skb, u8 prim) void llc_save_primitive(struct sk_buff* skb, u8 prim)
{ {
struct sockaddr_llc *addr = llc_ui_skb_cb(skb); struct sockaddr_llc *addr = llc_ui_skb_cb(skb);
/* save primitive for use by the user. */ /* save primitive for use by the user. */
addr->sllc_family = sk->family; addr->sllc_family = skb->sk->family;
addr->sllc_arphrd = skb->dev->type; addr->sllc_arphrd = skb->dev->type;
addr->sllc_test = prim == LLC_TEST_PRIM; addr->sllc_test = prim == LLC_TEST_PRIM;
addr->sllc_xid = prim == LLC_XID_PRIM; addr->sllc_xid = prim == LLC_XID_PRIM;
...@@ -67,110 +67,120 @@ void llc_save_primitive(struct sock *sk, struct sk_buff* skb, u8 prim) ...@@ -67,110 +67,120 @@ void llc_save_primitive(struct sock *sk, struct sk_buff* skb, u8 prim)
*/ */
int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
{ {
/* sending event to state machine */ int rc;
int rc = llc_conn_service(sk, skb);
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
u8 flag = ev->flag;
u8 status = ev->status;
struct llc_prim_if_block *ind_prim = ev->ind_prim;
struct llc_prim_if_block *cfm_prim = ev->cfm_prim;
/* ev->ind_prim = ev->cfm_prim = 0;
* FIXME: this will vanish as soon I get rid of the last prim crap rc = llc_conn_service(sk, skb); /* sending event to state machine */
*/ if (rc) {
if (flag != LLC_DATA_PRIM + 1 && flag != LLC_CONN_PRIM + 1 && printk(KERN_ERR "%s: llc_conn_service failed\n", __FUNCTION__);
flag != LLC_DISC_PRIM + 1) goto out_kfree_skb;
llc_conn_free_ev(skb); }
else if (ind_prim && cfm_prim)
skb_get(skb); if (!ev->ind_prim && !ev->cfm_prim) { /* indicate or confirm not required */
if (!flag) /* indicate or confirm not required */ if (!skb->list)
goto out_kfree_skb;
goto out; goto out;
rc = 0; }
if (ind_prim) { /* indication required */
/*
* FIXME: this will be saner as soon I get rid of the double
* sock crap
*/
switch (flag) {
case LLC_DATA_PRIM + 1:
llc_save_primitive(sk, skb, LLC_DATA_PRIM);
if (sock_queue_rcv_skb(sk, skb)) {
/*
* FIXME: have to sync the LLC state
* machine wrt mem usage with
* sk->{r,w}mem_alloc, will do
* this soon 8)
*/
printk(KERN_ERR
"%s: sock_queue_rcv_skb failed!\n",
__FUNCTION__);
kfree_skb(skb);
}
break;
case LLC_CONN_PRIM + 1: {
struct sock *parent = skb->sk;
skb->sk = sk; if (ev->ind_prim && ev->cfm_prim)
skb_queue_tail(&parent->receive_queue, skb); skb_get(skb);
sk->state_change(parent);
switch (ev->ind_prim) {
case LLC_DATA_PRIM:
llc_save_primitive(skb, LLC_DATA_PRIM);
if (sock_queue_rcv_skb(sk, skb)) {
/*
* shouldn't happen
*/
printk(KERN_ERR "%s: sock_queue_rcv_skb failed!\n",
__FUNCTION__);
kfree_skb(skb);
} }
break; break;
case LLC_DISC_PRIM + 1: case LLC_CONN_PRIM: {
sock_hold(sk); struct sock *parent = skb->sk;
if (sk->type == SOCK_STREAM && sk->state == TCP_ESTABLISHED) {
sk->shutdown = SHUTDOWN_MASK; skb->sk = sk;
sk->socket->state = SS_UNCONNECTED; skb_queue_tail(&parent->receive_queue, skb);
sk->state = TCP_CLOSE; sk->state_change(parent);
if (!sk->dead) { }
sk->state_change(sk); break;
sk->dead = 1; case LLC_DISC_PRIM:
} sock_hold(sk);
if (sk->type == SOCK_STREAM && sk->state == TCP_ESTABLISHED) {
sk->shutdown = SHUTDOWN_MASK;
sk->socket->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE;
if (!sk->dead) {
sk->state_change(sk);
sk->dead = 1;
} }
}
kfree_skb(skb);
sock_put(sk);
break;
case LLC_RESET_PRIM:
/*
* FIXME:
* RESET is not being notified to upper layers for now
*/
printk(KERN_INFO "%s: received a reset ind!\n", __FUNCTION__);
kfree_skb(skb);
break;
default:
if (ev->ind_prim) {
printk(KERN_INFO "%s: received unknown %d prim!\n",
__FUNCTION__, ev->ind_prim);
kfree_skb(skb); kfree_skb(skb);
sock_put(sk);
break;
default:
llc->sap->ind(ind_prim);
} }
/* No indication */
break;
} }
if (!cfm_prim) /* confirmation not required */
goto out; switch (ev->cfm_prim) {
/* FIXME: see FIXMEs above */ case LLC_DATA_PRIM:
switch (flag) {
case LLC_DATA_PRIM + 1:
if (!llc_data_accept_state(llc->state)) if (!llc_data_accept_state(llc->state))
/* In this state, we can send I pdu */
sk->write_space(sk); sk->write_space(sk);
else else
rc = llc->failed_data_req = 1; rc = llc->failed_data_req = 1;
break; break;
case LLC_CONN_PRIM + 1: case LLC_CONN_PRIM:
if (sk->type != SOCK_STREAM || sk->state != TCP_SYN_SENT) if (sk->type == SOCK_STREAM && sk->state == TCP_SYN_SENT) {
goto out_kfree_skb; if (ev->status) {
if (status) { sk->socket->state = SS_UNCONNECTED;
sk->socket->state = SS_UNCONNECTED; sk->state = TCP_CLOSE;
sk->state = TCP_CLOSE; } else {
} else { sk->socket->state = SS_CONNECTED;
sk->socket->state = SS_CONNECTED; sk->state = TCP_ESTABLISHED;
sk->state = TCP_ESTABLISHED; }
sk->state_change(sk);
} }
sk->state_change(sk);
break; break;
case LLC_DISC_PRIM + 1: case LLC_DISC_PRIM:
sock_hold(sk); sock_hold(sk);
if (sk->type != SOCK_STREAM || sk->state != TCP_CLOSING) { if (sk->type == SOCK_STREAM && sk->state == TCP_CLOSING) {
sock_put(sk); sk->socket->state = SS_UNCONNECTED;
goto out_kfree_skb; sk->state = TCP_CLOSE;
sk->state_change(sk);
} }
sk->socket->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE;
sk->state_change(sk);
sock_put(sk); sock_put(sk);
break; break;
case LLC_RESET_PRIM:
/*
* FIXME:
* RESET is not being notified to upper layers for now
*/
printk(KERN_INFO "%s: received a reset conf!\n", __FUNCTION__);
break;
default: default:
llc->sap->conf(cfm_prim); if (ev->cfm_prim) {
goto out; printk(KERN_INFO "%s: received unknown %d prim!\n",
__FUNCTION__, ev->cfm_prim);
break;
}
goto out; /* No confirmation */
} }
out_kfree_skb: out_kfree_skb:
kfree_skb(skb); kfree_skb(skb);
...@@ -198,9 +208,7 @@ void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb) ...@@ -198,9 +208,7 @@ void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
/* FIXME: indicate that we should send this to the upper layer */ ev->ind_prim = LLC_DATA_PRIM;
ev->flag = LLC_DATA_PRIM + 1;
ev->ind_prim = (void *)1;
} }
/** /**
...@@ -355,12 +363,14 @@ void llc_conn_free_ev(struct sk_buff *skb) ...@@ -355,12 +363,14 @@ void llc_conn_free_ev(struct sk_buff *skb)
/* free the frame that is bound to this event */ /* free the frame that is bound to this event */
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
if (LLC_PDU_TYPE_IS_I(pdu) || !ev->flag || !ev->ind_prim) if (LLC_PDU_TYPE_IS_I(pdu) || !ev->ind_prim)
kfree_skb(skb); kfree_skb(skb);
} else if (ev->type == LLC_CONN_EV_TYPE_PRIM && } else if (ev->type == LLC_CONN_EV_TYPE_PRIM &&
ev->data.prim.prim != LLC_DATA_PRIM) ev->data.prim.prim != LLC_DATA_PRIM)
kfree_skb(skb); kfree_skb(skb);
else if (ev->type == LLC_CONN_EV_TYPE_P_TMR) else if (ev->type == LLC_CONN_EV_TYPE_P_TMR ||
ev->type == LLC_CONN_EV_TYPE_BUSY_TMR ||
ev->type == LLC_CONN_EV_TYPE_REJ_TMR)
kfree_skb(skb); kfree_skb(skb);
} }
...@@ -540,6 +550,38 @@ struct sock *llc_lookup_listener(struct llc_sap *sap, struct llc_addr *laddr) ...@@ -540,6 +550,38 @@ struct sock *llc_lookup_listener(struct llc_sap *sap, struct llc_addr *laddr)
return rc; return rc;
} }
/**
* llc_lookup_dgram - Finds dgram socket for the local sap/mac
* @sap: SAP
* @laddr: address of local LLC (MAC + SAP)
*
* Search socket list of the SAP and finds connection using the local
* mac, and local sap. Returns pointer for socket found, %NULL otherwise.
*/
struct sock *llc_lookup_dgram(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_DGRAM &&
llc->laddr.lsap == laddr->lsap &&
llc_mac_match(llc->laddr.mac, laddr->mac)) {
rc = llc->sk;
break;
}
}
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.
......
...@@ -30,17 +30,16 @@ ...@@ -30,17 +30,16 @@
/** /**
* llc_sap_open - open interface to the upper layers. * llc_sap_open - open interface to the upper layers.
* @nw_indicate: pointer to indicate function of upper layer.
* @nw_confirm: pointer to confirm function of upper layer.
* @lsap: SAP number. * @lsap: SAP number.
* @sap: pointer to allocated SAP (output argument). * @func: rcv func for datalink protos
* *
* Interface function to upper layer. Each one who wants to get a SAP * Interface function to upper layer. Each one who wants to get a SAP
* (for example NetBEUI) should call this function. Returns the opened * (for example NetBEUI) should call this function. Returns the opened
* SAP for success, NULL for failure. * SAP for success, NULL for failure.
*/ */
struct llc_sap *llc_sap_open(llc_prim_call_t nw_indicate, struct llc_sap *llc_sap_open(u8 lsap, int (*func)(struct sk_buff *skb,
llc_prim_call_t nw_confirm, u8 lsap) struct net_device *dev,
struct packet_type *pt))
{ {
/* verify this SAP is not already open; if so, return error */ /* verify this SAP is not already open; if so, return error */
struct llc_sap *sap; struct llc_sap *sap;
...@@ -57,8 +56,7 @@ struct llc_sap *llc_sap_open(llc_prim_call_t nw_indicate, ...@@ -57,8 +56,7 @@ struct llc_sap *llc_sap_open(llc_prim_call_t nw_indicate,
goto err; goto err;
/* allocated a SAP; initialize it and clear out its memory pool */ /* allocated a SAP; initialize it and clear out its memory pool */
sap->laddr.lsap = lsap; sap->laddr.lsap = lsap;
sap->ind = nw_indicate; sap->rcv_func = func;
sap->conf = nw_confirm;
sap->parent_station = llc_station_get(); sap->parent_station = llc_station_get();
/* initialized SAP; add it to list of SAPs this station manages */ /* initialized SAP; add it to list of SAPs this station manages */
llc_sap_save(sap); llc_sap_save(sap);
...@@ -117,7 +115,7 @@ void llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb, ...@@ -117,7 +115,7 @@ void llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb,
ev->data.prim.prim = LLC_DATAUNIT_PRIM; ev->data.prim.prim = LLC_DATAUNIT_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_REQ; ev->data.prim.type = LLC_PRIM_TYPE_REQ;
ev->data.prim.data = &prim; ev->data.prim.data = &prim;
llc_sap_state_process(sap, skb); llc_sap_state_process(sap, skb, &llc_packet_type);
} }
/** /**
...@@ -130,8 +128,8 @@ void llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb, ...@@ -130,8 +128,8 @@ void llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb,
* This function is called when upper layer wants to send a TEST pdu. * This function is called when upper layer wants to send a TEST pdu.
* Returns 0 for success, 1 otherwise. * Returns 0 for success, 1 otherwise.
*/ */
void llc_build_and_send_test_pkt(struct llc_sap *sap, struct sk_buff *skb, void llc_build_and_send_test_pkt(struct llc_sap *sap,
u8 *dmac, u8 dsap) struct sk_buff *skb, u8 *dmac, u8 dsap)
{ {
union llc_u_prim_data prim_data; union llc_u_prim_data prim_data;
struct llc_prim_if_block prim; struct llc_prim_if_block prim;
...@@ -151,7 +149,7 @@ void llc_build_and_send_test_pkt(struct llc_sap *sap, struct sk_buff *skb, ...@@ -151,7 +149,7 @@ void llc_build_and_send_test_pkt(struct llc_sap *sap, struct sk_buff *skb,
ev->data.prim.prim = LLC_TEST_PRIM; ev->data.prim.prim = LLC_TEST_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_REQ; ev->data.prim.type = LLC_PRIM_TYPE_REQ;
ev->data.prim.data = &prim; ev->data.prim.data = &prim;
llc_sap_state_process(sap, skb); llc_sap_state_process(sap, skb, &llc_packet_type);
} }
/** /**
...@@ -185,7 +183,7 @@ void llc_build_and_send_xid_pkt(struct llc_sap *sap, struct sk_buff *skb, ...@@ -185,7 +183,7 @@ void llc_build_and_send_xid_pkt(struct llc_sap *sap, struct sk_buff *skb,
ev->data.prim.prim = LLC_XID_PRIM; ev->data.prim.prim = LLC_XID_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_REQ; ev->data.prim.type = LLC_PRIM_TYPE_REQ;
ev->data.prim.data = &prim; ev->data.prim.data = &prim;
llc_sap_state_process(sap, skb); llc_sap_state_process(sap, skb, &llc_packet_type);
} }
/** /**
......
...@@ -37,7 +37,8 @@ u8 llc_mac_null_var[IFHWADDRLEN]; ...@@ -37,7 +37,8 @@ u8 llc_mac_null_var[IFHWADDRLEN];
static void fix_up_incoming_skb(struct sk_buff *skb); static void fix_up_incoming_skb(struct sk_buff *skb);
static void llc_station_rcv(struct sk_buff *skb); static void llc_station_rcv(struct sk_buff *skb);
static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb); static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb,
struct packet_type *pt);
/** /**
* mac_send_pdu - Sends PDU to specific device. * mac_send_pdu - Sends PDU to specific device.
...@@ -82,7 +83,7 @@ int mac_send_pdu(struct sk_buff *skb) ...@@ -82,7 +83,7 @@ int mac_send_pdu(struct sk_buff *skb)
* data now), it queues this frame in the connection's backlog. * data now), it queues this frame in the connection's backlog.
*/ */
int llc_rcv(struct sk_buff *skb, struct net_device *dev, int llc_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt) struct packet_type *pt)
{ {
struct llc_sap *sap; struct llc_sap *sap;
struct llc_pdu_sn *pdu; struct llc_pdu_sn *pdu;
...@@ -113,8 +114,16 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -113,8 +114,16 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
} }
llc_decode_pdu_type(skb, &dest); llc_decode_pdu_type(skb, &dest);
if (dest == LLC_DEST_SAP) { /* type 1 services */ if (dest == LLC_DEST_SAP) { /* type 1 services */
dprintk("%s: calling llc_sap_rcv!\n", __FUNCTION__); struct llc_addr laddr;
llc_sap_rcv(sap, skb); struct sock *sk;
llc_pdu_decode_da(skb, laddr.mac);
llc_pdu_decode_dsap(skb, &laddr.lsap);
skb->sk = sk = llc_lookup_dgram(sap, &laddr);
llc_sap_rcv(sap, skb, pt);
if (sk)
sock_put(sk);
} else if (dest == LLC_DEST_CONN) { } else if (dest == LLC_DEST_CONN) {
struct llc_addr saddr, daddr; struct llc_addr saddr, daddr;
struct sock *sk; struct sock *sk;
...@@ -245,16 +254,18 @@ int llc_conn_rcv(struct sock* sk, struct sk_buff *skb) ...@@ -245,16 +254,18 @@ int llc_conn_rcv(struct sock* sk, struct sk_buff *skb)
* llc_sap_rcv - sends received pdus to the sap state machine * llc_sap_rcv - sends received pdus to the sap state machine
* @sap: current sap component structure. * @sap: current sap component structure.
* @skb: received frame. * @skb: received frame.
* @pt: packet type
* *
* Sends received pdus to the sap state machine. * Sends received pdus to the sap state machine.
*/ */
static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb) static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb,
struct packet_type *pt)
{ {
struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_sap_state_ev *ev = llc_sap_ev(skb);
ev->type = LLC_SAP_EV_TYPE_PDU; ev->type = LLC_SAP_EV_TYPE_PDU;
ev->reason = 0; ev->reason = 0;
llc_sap_state_process(sap, skb); llc_sap_state_process(sap, skb, pt);
} }
/** /**
......
...@@ -73,8 +73,6 @@ struct llc_sap *llc_sap_alloc(void) ...@@ -73,8 +73,6 @@ struct llc_sap *llc_sap_alloc(void)
spin_lock_init(&sap->sk_list.lock); spin_lock_init(&sap->sk_list.lock);
INIT_LIST_HEAD(&sap->sk_list.list); INIT_LIST_HEAD(&sap->sk_list.list);
skb_queue_head_init(&sap->mac_pdu_q); skb_queue_head_init(&sap->mac_pdu_q);
sap->llc_ind_prim.data = &sap->llc_ind_data_prim;
sap->llc_cfm_prim.data = &sap->llc_cfm_data_prim;
} }
return sap; return sap;
} }
...@@ -621,7 +619,7 @@ static int llc_proc_get_info(char *bf, char **start, off_t offset, int length) ...@@ -621,7 +619,7 @@ static int llc_proc_get_info(char *bf, char **start, off_t offset, int length)
return len; return len;
} }
static struct packet_type llc_packet_type = { struct packet_type llc_packet_type = {
.type = __constant_htons(ETH_P_802_2), .type = __constant_htons(ETH_P_802_2),
.func = llc_rcv, .func = llc_rcv,
.data = (void *)1, .data = (void *)1,
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <net/llc_s_ac.h> #include <net/llc_s_ac.h>
#include <net/llc_s_st.h> #include <net/llc_s_st.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_mac.h> #include <net/llc_mac.h>
#include <net/llc_pdu.h> #include <net/llc_pdu.h>
...@@ -63,21 +64,45 @@ void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk) ...@@ -63,21 +64,45 @@ void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk)
/** /**
* llc_sap_state_process - sends event to SAP state machine * llc_sap_state_process - sends event to SAP state machine
* @sap: pointer to SAP * @sap: sap to use
* @skb: pointer to occurred event * @skb: pointer to occurred event
* @pt: packet type, for datalink protos
* *
* After executing actions of the event, upper layer will be indicated * After executing actions of the event, upper layer will be indicated
* if needed(on receiving an UI frame). * if needed(on receiving an UI frame). sk can be null for the
* datalink_proto case.
*/ */
void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb) void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb,
struct packet_type *pt)
{ {
struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_sap_state_ev *ev = llc_sap_ev(skb);
llc_sap_next_state(sap, skb); llc_sap_next_state(sap, skb);
if (ev->ind_cfm_flag == LLC_IND) if (ev->ind_cfm_flag == LLC_IND) {
sap->ind(ev->prim); if (sap->rcv_func) {
else if (ev->type == LLC_SAP_EV_TYPE_PDU) /* FIXME:
* Ugly hack, still trying to figure it
* out if this is a bug in IPX or here
* in LLC Land... But hey, it even works,
* no leaks 8)
*/
if (skb->list)
skb_get(skb);
sap->rcv_func(skb, skb->dev, pt);
} else {
if (skb->sk->state == TCP_LISTEN)
goto drop;
llc_save_primitive(skb, ev->primitive);
/* queue skb to the user. */
if (sock_queue_rcv_skb(skb->sk, skb))
kfree_skb(skb);
}
} else if (ev->type == LLC_SAP_EV_TYPE_PDU) {
drop:
kfree_skb(skb); kfree_skb(skb);
}
} }
/** /**
...@@ -89,43 +114,18 @@ void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb) ...@@ -89,43 +114,18 @@ void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb)
{ {
struct llc_pdu_un *pdu; struct llc_pdu_un *pdu;
struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_sap_state_ev *ev = llc_sap_ev(skb);
struct llc_prim_if_block *prim = &sap->llc_ind_prim;
union llc_u_prim_data *prim_data = prim->data;
u8 lfb;
llc_pdu_decode_sa(skb, prim_data->udata.saddr.mac);
llc_pdu_decode_da(skb, prim_data->udata.daddr.mac);
llc_pdu_decode_dsap(skb, &prim_data->udata.daddr.lsap);
llc_pdu_decode_ssap(skb, &prim_data->udata.saddr.lsap);
prim_data->udata.pri = 0;
prim_data->udata.skb = skb;
pdu = llc_pdu_un_hdr(skb); pdu = llc_pdu_un_hdr(skb);
switch (LLC_U_PDU_RSP(pdu)) { switch (LLC_U_PDU_RSP(pdu)) {
case LLC_1_PDU_CMD_TEST: case LLC_1_PDU_CMD_TEST:
prim->prim = LLC_TEST_PRIM; ev->primitive = LLC_TEST_PRIM; break;
break; case LLC_1_PDU_CMD_XID:
case LLC_1_PDU_CMD_XID: ev->primitive = LLC_XID_PRIM; break;
prim->prim = LLC_XID_PRIM; case LLC_1_PDU_CMD_UI:
break; ev->primitive = LLC_DATAUNIT_PRIM; break;
case LLC_1_PDU_CMD_UI:
if (skb->protocol == ntohs(ETH_P_TR_802_2)) {
if (((struct trh_hdr *)skb->mac.raw)->rcf) {
lfb = ntohs(((struct trh_hdr *)
skb->mac.raw)->rcf) &
0x0070;
prim_data->udata.lfb = lfb >> 4;
} else {
lfb = 0xFF;
prim_data->udata.lfb = 0xFF;
}
}
prim->prim = LLC_DATAUNIT_PRIM;
break;
} }
prim->data = prim_data;
prim->sap = sap;
ev->ind_cfm_flag = LLC_IND; ev->ind_cfm_flag = LLC_IND;
ev->prim = prim; ev->prim = NULL;
} }
/** /**
......
This diff is collapsed.
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