Commit a0aaef1c authored by David S. Miller's avatar David S. Miller

Merge bk://kernel.bkbits.net/acme/llc-2.6

into nuts.ninka.net:/disk1/davem/BK/net-2.5
parents 91d4dbf2 874d7485
...@@ -9,7 +9,7 @@ menu "Token Ring devices" ...@@ -9,7 +9,7 @@ menu "Token Ring devices"
config TR config TR
bool "Token Ring driver support" bool "Token Ring driver support"
depends on (PCI || ISA || MCA || CCW) depends on (PCI || ISA || MCA || CCW)
select LLC_CORE select LLC
help help
Token Ring is IBM's way of communication on a local network; the Token Ring is IBM's way of communication on a local network; the
rest of the world uses Ethernet. To participate on a Token Ring rest of the world uses Ethernet. To participate on a Token Ring
......
#ifndef LLC_MAC_H #ifndef LLC_H
#define LLC_MAC_H #define LLC_H
/* /*
* Copyright (c) 1997 by Procom Technology, Inc. * Copyright (c) 1997 by Procom Technology, Inc.
* 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> * 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
...@@ -12,18 +12,80 @@ ...@@ -12,18 +12,80 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*/ */
#include <linux/if.h>
#include <linux/if_ether.h>
#include <linux/list.h>
#include <linux/spinlock.h>
struct net_device;
struct packet_type;
struct sk_buff;
struct llc_addr {
unsigned char lsap;
unsigned char mac[IFHWADDRLEN];
};
#define LLC_SAP_STATE_INACTIVE 1
#define LLC_SAP_STATE_ACTIVE 2
/**
* struct llc_sap - Defines the SAP component
*
* @station - station this sap belongs to
* @state - sap state
* @p_bit - only lowest-order bit used
* @f_bit - only lowest-order bit used
* @laddr - SAP value in this 'lsap'
* @node - entry in station sap_list
* @sk_list - LLC sockets this one manages
*/
struct llc_sap {
unsigned char state;
unsigned char p_bit;
unsigned char f_bit;
int (*rcv_func)(struct sk_buff *skb,
struct net_device *dev,
struct packet_type *pt);
struct llc_addr laddr;
struct list_head node;
struct {
rwlock_t lock;
struct hlist_head list;
} sk_list;
};
#define LLC_DEST_INVALID 0 /* Invalid LLC PDU type */ #define LLC_DEST_INVALID 0 /* Invalid LLC PDU type */
#define LLC_DEST_SAP 1 /* Type 1 goes here */ #define LLC_DEST_SAP 1 /* Type 1 goes here */
#define LLC_DEST_CONN 2 /* Type 2 goes here */ #define LLC_DEST_CONN 2 /* Type 2 goes here */
extern struct list_head llc_sap_list;
extern rwlock_t llc_sap_list_lock;
extern unsigned char llc_station_mac_sa[ETH_ALEN];
extern int llc_rcv(struct sk_buff *skb, struct net_device *dev, extern int llc_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt); struct packet_type *pt);
extern u16 lan_hdrs_init(struct sk_buff *skb, u8 *sa, u8 *da);
struct llc_sap; extern int llc_mac_hdr_init(struct sk_buff *skb,
struct sk_buff; unsigned char *sa, unsigned char *da);
extern void llc_add_pack(int type, void (*handler)(struct llc_sap *sap, extern void llc_add_pack(int type, void (*handler)(struct llc_sap *sap,
struct sk_buff *skb)); struct sk_buff *skb));
extern void llc_remove_pack(int type); extern void llc_remove_pack(int type);
#endif /* LLC_MAC_H */
extern void llc_set_station_handler(void (*handler)(struct sk_buff *skb));
extern struct llc_sap *llc_sap_open(unsigned char lsap,
int (*rcv)(struct sk_buff *skb,
struct net_device *dev,
struct packet_type *pt));
extern void llc_sap_close(struct llc_sap *sap);
extern struct llc_sap *llc_sap_find(unsigned char sap_value);
extern int llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb,
unsigned char *dmac, unsigned char dsap);
extern int llc_station_init(void);
extern void llc_station_exit(void);
#endif /* LLC_H */
#ifndef LLC_ACTN_H
#define LLC_ACTN_H
/*
* Copyright (c) 1997 by Procom Technology,Inc.
* 2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* This program can be redistributed or modified under the terms of the
* GNU General Public License as published by the Free Software Foundation.
* This program is distributed without any warranty or implied warranty
* of merchantability or fitness for a particular purpose.
*
* See the GNU General Public License for more details.
*/
/* Station component state transition actions */
#define LLC_STATION_AC_START_ACK_TMR 1
#define LLC_STATION_AC_SET_RETRY_CNT_0 2
#define LLC_STATION_AC_INC_RETRY_CNT_BY_1 3
#define LLC_STATION_AC_SET_XID_R_CNT_0 4
#define LLC_STATION_AC_INC_XID_R_CNT_BY_1 5
#define LLC_STATION_AC_SEND_NULL_DSAP_XID_C 6
#define LLC_STATION_AC_SEND_XID_R 7
#define LLC_STATION_AC_SEND_TEST_R 8
#define LLC_STATION_AC_REPORT_STATUS 9
/* All station state event action functions look like this */
typedef int (*llc_station_action_t)(struct llc_station *station,
struct sk_buff *skb);
extern int llc_station_ac_start_ack_timer(struct llc_station *station,
struct sk_buff *skb);
extern int llc_station_ac_set_retry_cnt_0(struct llc_station *station,
struct sk_buff *skb);
extern int llc_station_ac_inc_retry_cnt_by_1(struct llc_station *station,
struct sk_buff *skb);
extern int llc_station_ac_set_xid_r_cnt_0(struct llc_station *station,
struct sk_buff *skb);
extern int llc_station_ac_inc_xid_r_cnt_by_1(struct llc_station *station,
struct sk_buff *skb);
extern int llc_station_ac_send_null_dsap_xid_c(struct llc_station *station,
struct sk_buff *skb);
extern int llc_station_ac_send_xid_r(struct llc_station *station,
struct sk_buff *skb);
extern int llc_station_ac_send_test_r(struct llc_station *station,
struct sk_buff *skb);
extern int llc_station_ac_report_status(struct llc_station *station,
struct sk_buff *skb);
extern int llc_station_ac_report_status(struct llc_station *station,
struct sk_buff *skb);
extern void llc_station_ack_tmr_cb(unsigned long timeout_data);
#endif /* LLC_ACTN_H */
...@@ -15,6 +15,14 @@ ...@@ -15,6 +15,14 @@
#include <net/llc_if.h> #include <net/llc_if.h>
#include <linux/llc.h> #include <linux/llc.h>
#define LLC_EVENT 1
#define LLC_PACKET 2
#define LLC_P_TIME 2
#define LLC_ACK_TIME 1
#define LLC_REJ_TIME 3
#define LLC_BUSY_TIME 3
struct llc_timer { struct llc_timer {
struct timer_list timer; struct timer_list timer;
u16 expire; /* timer expire time */ u16 expire; /* timer expire time */
......
#ifndef LLC_EVNT_H
#define LLC_EVNT_H
/*
* Copyright (c) 1997 by Procom Technology,Inc.
* 2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* This program can be redistributed or modified under the terms of the
* GNU General Public License as published by the Free Software Foundation.
* This program is distributed without any warranty or implied warranty
* of merchantability or fitness for a particular purpose.
*
* See the GNU General Public License for more details.
*/
/* Station component state transition events */
/* Types of events (possible values in 'ev->type') */
#define LLC_STATION_EV_TYPE_SIMPLE 1
#define LLC_STATION_EV_TYPE_CONDITION 2
#define LLC_STATION_EV_TYPE_PRIM 3
#define LLC_STATION_EV_TYPE_PDU 4 /* command/response PDU */
#define LLC_STATION_EV_TYPE_ACK_TMR 5
#define LLC_STATION_EV_TYPE_RPT_STATUS 6
/* Events */
#define LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK 1
#define LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK 2
#define LLC_STATION_EV_ACK_TMR_EXP_LT_RETRY_CNT_MAX_RETRY 3
#define LLC_STATION_EV_ACK_TMR_EXP_EQ_RETRY_CNT_MAX_RETRY 4
#define LLC_STATION_EV_RX_NULL_DSAP_XID_C 5
#define LLC_STATION_EV_RX_NULL_DSAP_0_XID_R_XID_R_CNT_EQ 6
#define LLC_STATION_EV_RX_NULL_DSAP_1_XID_R_XID_R_CNT_EQ 7
#define LLC_STATION_EV_RX_NULL_DSAP_TEST_C 8
#define LLC_STATION_EV_DISABLE_REQ 9
struct llc_station_state_ev {
u8 type;
u8 prim;
u8 prim_type;
u8 reason;
struct list_head node; /* node in station->ev_q.list */
};
static __inline__ struct llc_station_state_ev *
llc_station_ev(struct sk_buff *skb)
{
return (struct llc_station_state_ev *)skb->cb;
}
typedef int (*llc_station_ev_t)(struct llc_station *station,
struct sk_buff *skb);
extern int llc_stat_ev_enable_with_dup_addr_check(struct llc_station *station,
struct sk_buff *skb);
extern int llc_stat_ev_enable_without_dup_addr_check(struct llc_station *station,
struct sk_buff *skb);
extern int llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry(struct llc_station *
station,
struct sk_buff *skb);
extern int llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry(struct llc_station *station,
struct sk_buff *skb);
extern int llc_stat_ev_rx_null_dsap_xid_c(struct llc_station *station,
struct sk_buff *skb);
extern int llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq(struct llc_station *station,
struct sk_buff *skb);
extern int llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq(struct llc_station *station,
struct sk_buff *skb);
extern int llc_stat_ev_rx_null_dsap_test_c(struct llc_station *station,
struct sk_buff *skb);
extern int llc_stat_ev_disable_req(struct llc_station *station,
struct sk_buff *skb);
#endif /* LLC_EVNT_H */
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#include <linux/if.h> #include <linux/if.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/llc.h> #include <linux/llc.h>
#include <net/llc.h>
#define LLC_DATAUNIT_PRIM 1 #define LLC_DATAUNIT_PRIM 1
#define LLC_CONN_PRIM 2 #define LLC_CONN_PRIM 2
...@@ -60,13 +61,6 @@ ...@@ -60,13 +61,6 @@
#define LLC_STATUS_CONFLICT 7 /* disconnect conn */ #define LLC_STATUS_CONFLICT 7 /* disconnect conn */
#define LLC_STATUS_RESET_DONE 8 /* */ #define LLC_STATUS_RESET_DONE 8 /* */
/* Structures and types */
/* SAP/MAC Address pair */
struct llc_addr {
u8 lsap;
u8 mac[IFHWADDRLEN];
};
extern u8 llc_mac_null_var[IFHWADDRLEN]; extern u8 llc_mac_null_var[IFHWADDRLEN];
/** /**
......
#ifndef LLC_MAIN_H
#define LLC_MAIN_H
/*
* Copyright (c) 1997 by Procom Technology, Inc.
* 2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* This program can be redistributed or modified under the terms of the
* GNU General Public License as published by the Free Software Foundation.
* This program is distributed without any warranty or implied warranty
* of merchantability or fitness for a particular purpose.
*
* See the GNU General Public License for more details.
*/
#define LLC_EVENT 1
#define LLC_PACKET 2
#define LLC_TYPE_1 1
#define LLC_TYPE_2 2
#define LLC_P_TIME 2
#define LLC_ACK_TIME 1
#define LLC_REJ_TIME 3
#define LLC_BUSY_TIME 3
/**
* struct llc_station - LLC station component
*
* SAP and connection resource manager, one per adapter.
*
* @state - state of station
* @xid_r_count - XID response PDU counter
* @mac_sa - MAC source address
* @sap_list - list of related SAPs
* @ev_q - events entering state mach.
* @mac_pdu_q - PDUs ready to send to MAC
*/
struct llc_station {
u8 state;
u8 xid_r_count;
struct timer_list ack_timer;
u8 retry_count;
u8 maximum_retry;
u8 mac_sa[6];
struct {
rwlock_t lock;
struct list_head list;
} sap_list;
struct {
struct sk_buff_head list;
spinlock_t lock;
} ev_q;
struct sk_buff_head mac_pdu_q;
};
extern struct llc_sap *llc_sap_alloc(void);
extern void llc_sap_save(struct llc_sap *sap);
extern void llc_free_sap(struct llc_sap *sap);
extern struct llc_sap *llc_sap_find(u8 lsap);
extern void llc_station_state_process(struct llc_station *station,
struct sk_buff *skb);
extern void llc_station_send_pdu(struct llc_station *station,
struct sk_buff *skb);
extern struct sk_buff *llc_alloc_frame(void);
extern struct llc_station llc_main_station;
#endif /* LLC_MAIN_H */
...@@ -11,10 +11,7 @@ ...@@ -11,10 +11,7 @@
* *
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*/ */
/* Defines SAP component states */
#define LLC_SAP_STATE_INACTIVE 1
#define LLC_SAP_STATE_ACTIVE 2
#define LLC_NR_SAP_STATES 2 /* size of state table */ #define LLC_NR_SAP_STATES 2 /* size of state table */
/* structures and types */ /* structures and types */
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#define LLC_SAP_H #define LLC_SAP_H
/* /*
* Copyright (c) 1997 by Procom Technology,Inc. * Copyright (c) 1997 by Procom Technology,Inc.
* 2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> * 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
* *
* This program can be redistributed or modified under the terms of the * This program can be redistributed or modified under the terms of the
* GNU General Public License as published by the Free Software Foundation. * GNU General Public License as published by the Free Software Foundation.
...@@ -11,50 +11,20 @@ ...@@ -11,50 +11,20 @@
* *
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*/ */
#include <linux/skbuff.h> struct llc_sap;
#include <net/llc_if.h> struct sk_buff;
/**
* struct llc_sap - Defines the SAP component
*
* @station - station this sap belongs to
* @state - sap state
* @p_bit - only lowest-order bit used
* @f_bit - only lowest-order bit used
* @laddr - SAP value in this 'lsap'
* @node - entry in station sap_list
* @sk_list - LLC sockets this one manages
*/
struct llc_sap {
struct llc_station *station;
u8 state;
u8 p_bit;
u8 f_bit;
int (*rcv_func)(struct sk_buff *skb,
struct net_device *dev,
struct packet_type *pt);
struct llc_addr laddr;
struct list_head node;
struct {
rwlock_t lock;
struct hlist_head list;
} sk_list;
};
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);
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_save_primitive(struct sk_buff* skb, u8 prim); extern void llc_save_primitive(struct sk_buff* skb, unsigned char prim);
extern struct sk_buff *llc_alloc_frame(void);
extern struct llc_sap *llc_sap_open(u8 lsap,
int (*rcv)(struct sk_buff *skb,
struct net_device *dev,
struct packet_type *pt));
extern void llc_sap_close(struct llc_sap *sap);
extern void llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb,
u8 *dmac, u8 dsap);
extern void llc_build_and_send_xid_pkt(struct llc_sap *sap, struct sk_buff *skb,
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, u8 *dmac, u8 dsap); struct sk_buff *skb,
unsigned char *dmac,
unsigned char dsap);
extern void llc_build_and_send_xid_pkt(struct llc_sap *sap,
struct sk_buff *skb,
unsigned char *dmac,
unsigned char dsap);
#endif /* LLC_SAP_H */ #endif /* LLC_SAP_H */
#ifndef LLC_STAT_H
#define LLC_STAT_H
/*
* Copyright (c) 1997 by Procom Technology,Inc.
* 2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* This program can be redistributed or modified under the terms of the
* GNU General Public License as published by the Free Software Foundation.
* This program is distributed without any warranty or implied warranty
* of merchantability or fitness for a particular purpose.
*
* See the GNU General Public License for more details.
*/
/* Station component state table */
/* Station component states */
#define LLC_STATION_STATE_DOWN 1 /* initial state */
#define LLC_STATION_STATE_DUP_ADDR_CHK 2
#define LLC_STATION_STATE_UP 3
#define LLC_NBR_STATION_STATES 3 /* size of state table */
/* Station component state table structure */
struct llc_station_state_trans {
llc_station_ev_t ev;
u8 next_state;
llc_station_action_t *ev_actions;
};
struct llc_station_state {
u8 curr_state;
struct llc_station_state_trans **transitions;
};
extern struct llc_station_state llc_station_state_table[LLC_NBR_STATION_STATES];
#endif /* LLC_STAT_H */
...@@ -22,8 +22,8 @@ ...@@ -22,8 +22,8 @@
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/init.h> #include <linux/init.h>
#include <net/llc.h>
#include <net/p8022.h> #include <net/p8022.h>
#include <net/llc_sap.h>
static int p8022_request(struct datalink_proto *dl, struct sk_buff *skb, static int p8022_request(struct datalink_proto *dl, struct sk_buff *skb,
unsigned char *dest) unsigned char *dest)
......
...@@ -15,8 +15,8 @@ ...@@ -15,8 +15,8 @@
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <net/datalink.h> #include <net/datalink.h>
#include <net/llc.h>
#include <net/psnap.h> #include <net/psnap.h>
#include <net/llc_sap.h>
#include <linux/mm.h> #include <linux/mm.h>
#include <linux/in.h> #include <linux/in.h>
#include <linux/init.h> #include <linux/init.h>
......
...@@ -374,7 +374,7 @@ source "net/llc/Kconfig" ...@@ -374,7 +374,7 @@ source "net/llc/Kconfig"
config IPX config IPX
tristate "The IPX protocol" tristate "The IPX protocol"
select LLC_CORE select LLC
---help--- ---help---
This is support for the Novell networking protocol, IPX, commonly This is support for the Novell networking protocol, IPX, commonly
used for local networks of Windows machines. You need it if you used for local networks of Windows machines. You need it if you
...@@ -411,7 +411,7 @@ source "net/ipx/Kconfig" ...@@ -411,7 +411,7 @@ source "net/ipx/Kconfig"
config ATALK config ATALK
tristate "Appletalk protocol support" tristate "Appletalk protocol support"
select LLC_CORE select LLC
---help--- ---help---
AppleTalk is the protocol that Apple computers can use to communicate AppleTalk is the protocol that Apple computers can use to communicate
on a network. If your Linux box is connected to such a network and you on a network. If your Linux box is connected to such a network and you
......
...@@ -12,7 +12,7 @@ obj-$(CONFIG_NET) := socket.o core/ ...@@ -12,7 +12,7 @@ obj-$(CONFIG_NET) := socket.o core/
obj-$(CONFIG_COMPAT) += compat.o obj-$(CONFIG_COMPAT) += compat.o
# LLC has to be linked before the files in net/802/ # LLC has to be linked before the files in net/802/
obj-$(CONFIG_LLC_CORE) += llc/ obj-$(CONFIG_LLC) += llc/
obj-$(CONFIG_NET) += ethernet/ 802/ sched/ netlink/ obj-$(CONFIG_NET) += ethernet/ 802/ sched/ netlink/
obj-$(CONFIG_INET) += ipv4/ xfrm/ obj-$(CONFIG_INET) += ipv4/ xfrm/
obj-$(CONFIG_UNIX) += unix/ obj-$(CONFIG_UNIX) += unix/
......
config LLC_CORE config LLC
tristate tristate
depends on NET depends on NET
config LLC2 config LLC2
tristate "ANSI/IEEE 802.2 LLC type 2 Support" tristate "ANSI/IEEE 802.2 LLC type 2 Support"
select LLC_CORE select LLC
help help
This is a Logical Link Layer type 2, connection oriented support. This is a Logical Link Layer type 2, connection oriented support.
Select this if you want to have support for PF_LLC sockets. Select this if you want to have support for PF_LLC sockets.
...@@ -12,14 +12,13 @@ ...@@ -12,14 +12,13 @@
# See the GNU General Public License for more details. # See the GNU General Public License for more details.
########################################################################### ###########################################################################
obj-$(CONFIG_LLC_CORE) += llc_core.o obj-$(CONFIG_LLC) += llc.o
llc_core-y := llc_mac.o llc_sap.o llc_s_st.o llc_s_ac.o llc_s_ev.o llc_main.o \ llc-y := llc_core.o llc_input.o llc_output.o
llc_actn.o llc_stat.o llc_evnt.o
obj-$(CONFIG_LLC2) += llc2.o obj-$(CONFIG_LLC2) += llc2.o
llc2-y := llc_if.o llc_c_ev.o llc_c_ac.o llc_conn.o llc_c_st.o llc_pdu.o \ llc2-y := llc_if.o llc_c_ev.o llc_c_ac.o llc_conn.o llc_c_st.o llc_pdu.o \
af_llc.o llc_sap.o llc_s_ac.o llc_s_ev.o llc_s_st.o af_llc.o llc_station.o
llc2-$(CONFIG_PROC_FS) += llc_proc.o llc2-$(CONFIG_PROC_FS) += llc_proc.o
...@@ -24,14 +24,13 @@ ...@@ -24,14 +24,13 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/tcp.h> #include <linux/tcp.h>
#include <linux/rtnetlink.h>
#include <linux/init.h>
#include <net/llc.h>
#include <net/llc_sap.h> #include <net/llc_sap.h>
#include <net/llc_pdu.h> #include <net/llc_pdu.h>
#include <net/llc_conn.h> #include <net/llc_conn.h>
#include <net/llc_mac.h>
#include <net/llc_main.h>
#include <net/llc_proc.h> #include <net/llc_proc.h>
#include <linux/rtnetlink.h>
#include <linux/init.h>
/* remember: uninitialized global data is zeroed because its in .bss */ /* remember: uninitialized global data is zeroed because its in .bss */
static u16 llc_ui_sap_last_autoport = LLC_SAP_DYN_START; static u16 llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
...@@ -1053,6 +1052,7 @@ static int __init llc2_init(void) ...@@ -1053,6 +1052,7 @@ static int __init llc2_init(void)
int rc; int rc;
llc_build_offset_table(); llc_build_offset_table();
llc_station_init();
llc_ui_sap_last_autoport = LLC_SAP_DYN_START; llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
rc = llc_proc_init(); rc = llc_proc_init();
if (!rc) { if (!rc) {
...@@ -1065,6 +1065,7 @@ static int __init llc2_init(void) ...@@ -1065,6 +1065,7 @@ static int __init llc2_init(void)
static void __exit llc2_exit(void) static void __exit llc2_exit(void)
{ {
llc_station_exit();
llc_remove_pack(LLC_DEST_SAP); llc_remove_pack(LLC_DEST_SAP);
llc_remove_pack(LLC_DEST_CONN); llc_remove_pack(LLC_DEST_CONN);
sock_unregister(PF_LLC); sock_unregister(PF_LLC);
......
/*
* llc_actn.c - Implementation of actions of station component of LLC
*
* Description :
* Functions in this module are implementation of station component actions.
* Details of actions can be found in IEEE-802.2 standard document.
* All functions have one station and one event as input argument. All of
* them return 0 On success and 1 otherwise.
*
* Copyright (c) 1997 by Procom Technology, Inc.
* 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* This program can be redistributed or modified under the terms of the
* GNU General Public License as published by the Free Software Foundation.
* This program is distributed without any warranty or implied warranty
* of merchantability or fitness for a particular purpose.
*
* See the GNU General Public License for more details.
*/
#include <linux/netdevice.h>
#include <net/llc_if.h>
#include <net/llc_main.h>
#include <net/llc_evnt.h>
#include <net/llc_pdu.h>
#include <net/llc_mac.h>
int llc_station_ac_start_ack_timer(struct llc_station *station,
struct sk_buff *skb)
{
mod_timer(&station->ack_timer, jiffies + LLC_ACK_TIME * HZ);
return 0;
}
int llc_station_ac_set_retry_cnt_0(struct llc_station *station,
struct sk_buff *skb)
{
station->retry_count = 0;
return 0;
}
int llc_station_ac_inc_retry_cnt_by_1(struct llc_station *station,
struct sk_buff *skb)
{
station->retry_count++;
return 0;
}
int llc_station_ac_set_xid_r_cnt_0(struct llc_station *station,
struct sk_buff *skb)
{
station->xid_r_count = 0;
return 0;
}
int llc_station_ac_inc_xid_r_cnt_by_1(struct llc_station *station,
struct sk_buff *skb)
{
station->xid_r_count++;
return 0;
}
int llc_station_ac_send_null_dsap_xid_c(struct llc_station *station,
struct sk_buff *skb)
{
int rc = 1;
struct sk_buff *nskb = llc_alloc_frame();
if (!nskb)
goto out;
rc = 0;
llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, 0, LLC_PDU_CMD);
llc_pdu_init_as_xid_cmd(nskb, LLC_XID_NULL_CLASS_2, 127);
lan_hdrs_init(nskb, station->mac_sa, station->mac_sa);
llc_station_send_pdu(station, nskb);
out:
return rc;
}
int llc_station_ac_send_xid_r(struct llc_station *station,
struct sk_buff *skb)
{
u8 mac_da[ETH_ALEN], dsap;
int rc = 1;
struct sk_buff* nskb = llc_alloc_frame();
if (!nskb)
goto out;
rc = 0;
nskb->dev = skb->dev;
llc_pdu_decode_sa(skb, mac_da);
llc_pdu_decode_ssap(skb, &dsap);
llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 127);
lan_hdrs_init(nskb, station->mac_sa, mac_da);
llc_station_send_pdu(station, nskb);
out:
return rc;
}
int llc_station_ac_send_test_r(struct llc_station *station,
struct sk_buff *skb)
{
u8 mac_da[ETH_ALEN], dsap;
int rc = 1;
struct sk_buff *nskb = llc_alloc_frame();
if (!nskb)
goto out;
rc = 0;
nskb->dev = skb->dev;
llc_pdu_decode_sa(skb, mac_da);
llc_pdu_decode_ssap(skb, &dsap);
llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
llc_pdu_init_as_test_rsp(nskb, skb);
lan_hdrs_init(nskb, station->mac_sa, mac_da);
llc_station_send_pdu(station, nskb);
out:
return rc;
}
int llc_station_ac_report_status(struct llc_station *station,
struct sk_buff *skb)
{
return 0;
}
void llc_station_ack_tmr_cb(unsigned long timeout_data)
{
struct llc_station *station = (struct llc_station *)timeout_data;
struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
if (skb) {
struct llc_station_state_ev *ev = llc_station_ev(skb);
ev->type = LLC_STATION_EV_TYPE_ACK_TMR;
llc_station_state_process(station, skb);
}
}
...@@ -21,12 +21,13 @@ ...@@ -21,12 +21,13 @@
#include <net/llc_conn.h> #include <net/llc_conn.h>
#include <net/llc_sap.h> #include <net/llc_sap.h>
#include <net/sock.h> #include <net/sock.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>
#include <net/llc_c_st.h> #include <net/llc_c_st.h>
#include <net/llc_pdu.h> #include <net/llc_pdu.h>
#include <net/llc_mac.h> #include <net/llc.h>
#include "llc_output.h"
static int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb); static int llc_conn_ac_inc_vs_by_1(struct sock *sk, struct sk_buff *skb);
static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb); static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb);
...@@ -52,7 +53,7 @@ int llc_conn_ac_clear_remote_busy(struct sock *sk, struct sk_buff *skb) ...@@ -52,7 +53,7 @@ int llc_conn_ac_clear_remote_busy(struct sock *sk, struct sk_buff *skb)
int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOTCONN;
u8 dsap; u8 dsap;
struct llc_sap *sap; struct llc_sap *sap;
...@@ -97,28 +98,24 @@ int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb) ...@@ -97,28 +98,24 @@ int llc_conn_ac_disc_ind(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);
u8 reason = 0; u8 reason = 0;
int rc = 1; int rc = 0;
if (ev->type == LLC_CONN_EV_TYPE_PDU) { if (ev->type == LLC_CONN_EV_TYPE_PDU) {
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
if (LLC_PDU_IS_RSP(pdu) && if (LLC_PDU_IS_RSP(pdu) &&
LLC_PDU_TYPE_IS_U(pdu) && LLC_PDU_TYPE_IS_U(pdu) &&
LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_DM) { LLC_U_PDU_RSP(pdu) == LLC_2_PDU_RSP_DM)
reason = LLC_DISC_REASON_RX_DM_RSP_PDU; reason = LLC_DISC_REASON_RX_DM_RSP_PDU;
rc = 0; else if (LLC_PDU_IS_CMD(pdu) &&
} else if (LLC_PDU_IS_CMD(pdu) &&
LLC_PDU_TYPE_IS_U(pdu) && LLC_PDU_TYPE_IS_U(pdu) &&
LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_DISC) { LLC_U_PDU_CMD(pdu) == LLC_2_PDU_CMD_DISC)
reason = LLC_DISC_REASON_RX_DISC_CMD_PDU; reason = LLC_DISC_REASON_RX_DISC_CMD_PDU;
rc = 0; } else if (ev->type == LLC_CONN_EV_TYPE_ACK_TMR)
}
} else if (ev->type == LLC_CONN_EV_TYPE_ACK_TMR) {
reason = LLC_DISC_REASON_ACK_TMR_EXP; reason = LLC_DISC_REASON_ACK_TMR_EXP;
rc = 0; else {
} else {
reason = 0; reason = 0;
rc = 1; rc = -EINVAL;
} }
if (!rc) { if (!rc) {
ev->reason = reason; ev->reason = reason;
...@@ -217,29 +214,33 @@ int llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2(struct sock *sk, ...@@ -217,29 +214,33 @@ int llc_conn_ac_stop_rej_tmr_if_data_flag_eq_2(struct sock *sk,
int llc_conn_ac_send_disc_cmd_p_set_x(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_disc_cmd_p_set_x(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
u8 p_bit = 1;
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap; struct llc_sap *sap = llc->sap;
nskb->dev = llc->dev; nskb->dev = llc->dev;
llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_CMD); llc->daddr.lsap, LLC_PDU_CMD);
llc_pdu_init_as_disc_cmd(nskb, p_bit); llc_pdu_init_as_disc_cmd(nskb, 1);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
llc_conn_ac_set_p_flag_1(sk, skb);
} }
llc_conn_ac_set_p_flag_1(sk, skb); out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_send_dm_rsp_f_set_p(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_dm_rsp_f_set_p(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
...@@ -252,16 +253,21 @@ int llc_conn_ac_send_dm_rsp_f_set_p(struct sock *sk, struct sk_buff *skb) ...@@ -252,16 +253,21 @@ int llc_conn_ac_send_dm_rsp_f_set_p(struct sock *sk, struct sk_buff *skb)
llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_dm_rsp(nskb, f_bit); llc_pdu_init_as_dm_rsp(nskb, f_bit);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_send_dm_rsp_f_set_1(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_dm_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
...@@ -273,16 +279,21 @@ int llc_conn_ac_send_dm_rsp_f_set_1(struct sock *sk, struct sk_buff *skb) ...@@ -273,16 +279,21 @@ int llc_conn_ac_send_dm_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_dm_rsp(nskb, f_bit); llc_pdu_init_as_dm_rsp(nskb, f_bit);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_send_dm_rsp_f_set_f_flag(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_dm_rsp_f_set_f_flag(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
...@@ -294,17 +305,22 @@ int llc_conn_ac_send_dm_rsp_f_set_f_flag(struct sock *sk, struct sk_buff *skb) ...@@ -294,17 +305,22 @@ int llc_conn_ac_send_dm_rsp_f_set_f_flag(struct sock *sk, struct sk_buff *skb)
llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_dm_rsp(nskb, f_bit); llc_pdu_init_as_dm_rsp(nskb, f_bit);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_send_frmr_rsp_f_set_x(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_frmr_rsp_f_set_x(struct sock *sk, struct sk_buff *skb)
{ {
u8 f_bit; u8 f_bit;
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb; struct sk_buff *nskb;
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
...@@ -323,16 +339,21 @@ int llc_conn_ac_send_frmr_rsp_f_set_x(struct sock *sk, struct sk_buff *skb) ...@@ -323,16 +339,21 @@ int llc_conn_ac_send_frmr_rsp_f_set_x(struct sock *sk, struct sk_buff *skb)
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_frmr_rsp(nskb, pdu, f_bit, llc->vS, llc_pdu_init_as_frmr_rsp(nskb, pdu, f_bit, llc->vS,
llc->vR, INCORRECT); llc->vR, INCORRECT);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_resend_frmr_rsp_f_set_0(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_resend_frmr_rsp_f_set_0(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
...@@ -346,17 +367,22 @@ int llc_conn_ac_resend_frmr_rsp_f_set_0(struct sock *sk, struct sk_buff *skb) ...@@ -346,17 +367,22 @@ int llc_conn_ac_resend_frmr_rsp_f_set_0(struct sock *sk, struct sk_buff *skb)
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_frmr_rsp(nskb, pdu, f_bit, llc->vS, llc_pdu_init_as_frmr_rsp(nskb, pdu, f_bit, llc->vS,
llc->vR, INCORRECT); llc->vR, INCORRECT);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_resend_frmr_rsp_f_set_p(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_resend_frmr_rsp_f_set_p(struct sock *sk, struct sk_buff *skb)
{ {
u8 f_bit; u8 f_bit;
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb; struct sk_buff *nskb;
llc_pdu_decode_pf_bit(skb, &f_bit); llc_pdu_decode_pf_bit(skb, &f_bit);
...@@ -371,41 +397,50 @@ int llc_conn_ac_resend_frmr_rsp_f_set_p(struct sock *sk, struct sk_buff *skb) ...@@ -371,41 +397,50 @@ int llc_conn_ac_resend_frmr_rsp_f_set_p(struct sock *sk, struct sk_buff *skb)
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_frmr_rsp(nskb, pdu, f_bit, llc->vS, llc_pdu_init_as_frmr_rsp(nskb, pdu, f_bit, llc->vS,
llc->vR, INCORRECT); llc->vR, INCORRECT);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_send_i_cmd_p_set_1(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_i_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
{ {
u8 p_bit = 1; int rc;
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap; struct llc_sap *sap = llc->sap;
llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap, llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_CMD); llc->daddr.lsap, LLC_PDU_CMD);
llc_pdu_init_as_i_cmd(skb, p_bit, llc->vS, llc->vR); llc_pdu_init_as_i_cmd(skb, 1, llc->vS, llc->vR);
lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac);
llc_conn_send_pdu(sk, skb); if (!rc) {
llc_conn_ac_inc_vs_by_1(sk, skb); llc_conn_send_pdu(sk, skb);
return 0; llc_conn_ac_inc_vs_by_1(sk, skb);
}
return rc;
} }
int llc_conn_ac_send_i_cmd_p_set_0(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_i_cmd_p_set_0(struct sock *sk, struct sk_buff *skb)
{ {
u8 p_bit = 0; int rc;
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap; struct llc_sap *sap = llc->sap;
llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap, llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_CMD); llc->daddr.lsap, LLC_PDU_CMD);
llc_pdu_init_as_i_cmd(skb, p_bit, llc->vS, llc->vR); llc_pdu_init_as_i_cmd(skb, 0, llc->vS, llc->vR);
lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac);
llc_conn_send_pdu(sk, skb); if (!rc) {
llc_conn_ac_inc_vs_by_1(sk, skb); llc_conn_send_pdu(sk, skb);
return 0; llc_conn_ac_inc_vs_by_1(sk, skb);
}
return rc;
} }
int llc_conn_ac_resend_i_cmd_p_set_1(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_resend_i_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
...@@ -431,16 +466,18 @@ int llc_conn_ac_resend_i_cmd_p_set_1_or_send_rr(struct sock *sk, ...@@ -431,16 +466,18 @@ int llc_conn_ac_resend_i_cmd_p_set_1_or_send_rr(struct sock *sk,
int llc_conn_ac_send_i_xxx_x_set_0(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_i_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
{ {
u8 p_bit = 0; int rc;
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap; struct llc_sap *sap = llc->sap;
llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap, llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_CMD); llc->daddr.lsap, LLC_PDU_CMD);
llc_pdu_init_as_i_cmd(skb, p_bit, llc->vS, llc->vR); llc_pdu_init_as_i_cmd(skb, 0, llc->vS, llc->vR);
lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac);
llc_conn_send_pdu(sk, skb); if (!rc) {
llc_conn_ac_inc_vs_by_1(sk, skb); llc_conn_send_pdu(sk, skb);
llc_conn_ac_inc_vs_by_1(sk, skb);
}
return 0; return 0;
} }
...@@ -457,9 +494,8 @@ int llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr(struct sock *sk, ...@@ -457,9 +494,8 @@ int llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr(struct sock *sk,
struct sk_buff *skb) struct sk_buff *skb)
{ {
u8 nr; u8 nr;
u8 f_bit = 0;
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
...@@ -469,15 +505,17 @@ int llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr(struct sock *sk, ...@@ -469,15 +505,17 @@ int llc_conn_ac_resend_i_xxx_x_set_0_or_send_rr(struct sock *sk,
nskb->dev = llc->dev; nskb->dev = llc->dev;
llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_rr_rsp(nskb, f_bit, llc->vR); llc_pdu_init_as_rr_rsp(nskb, 0, llc->vR);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (!rc)
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
else
kfree_skb(skb);
} }
if (rc) { if (rc) {
nr = LLC_I_GET_NR(pdu); nr = LLC_I_GET_NR(pdu);
rc = 0; rc = 0;
llc_conn_resend_i_pdu_as_cmd(sk, nr, f_bit); llc_conn_resend_i_pdu_as_cmd(sk, nr, 0);
} }
return rc; return rc;
} }
...@@ -493,28 +531,32 @@ int llc_conn_ac_resend_i_rsp_f_set_1(struct sock *sk, struct sk_buff *skb) ...@@ -493,28 +531,32 @@ int llc_conn_ac_resend_i_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
int llc_conn_ac_send_rej_cmd_p_set_1(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_rej_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap; struct llc_sap *sap = llc->sap;
u8 p_bit = 1;
nskb->dev = llc->dev; nskb->dev = llc->dev;
llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_CMD); llc->daddr.lsap, LLC_PDU_CMD);
llc_pdu_init_as_rej_cmd(nskb, p_bit, llc->vR); llc_pdu_init_as_rej_cmd(nskb, 1, llc->vR);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_send_rej_rsp_f_set_1(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_rej_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
...@@ -526,16 +568,21 @@ int llc_conn_ac_send_rej_rsp_f_set_1(struct sock *sk, struct sk_buff *skb) ...@@ -526,16 +568,21 @@ int llc_conn_ac_send_rej_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_rej_rsp(nskb, f_bit, llc->vR); llc_pdu_init_as_rej_rsp(nskb, f_bit, llc->vR);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_send_rej_xxx_x_set_0(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_rej_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
...@@ -547,37 +594,46 @@ int llc_conn_ac_send_rej_xxx_x_set_0(struct sock *sk, struct sk_buff *skb) ...@@ -547,37 +594,46 @@ int llc_conn_ac_send_rej_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_rej_rsp(nskb, f_bit, llc->vR); llc_pdu_init_as_rej_rsp(nskb, f_bit, llc->vR);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_send_rnr_cmd_p_set_1(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_rnr_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap; struct llc_sap *sap = llc->sap;
u8 p_bit = 1;
nskb->dev = llc->dev; nskb->dev = llc->dev;
llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_CMD); llc->daddr.lsap, LLC_PDU_CMD);
llc_pdu_init_as_rnr_cmd(nskb, p_bit, llc->vR); llc_pdu_init_as_rnr_cmd(nskb, 1, llc->vR);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_send_rnr_rsp_f_set_1(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_rnr_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
...@@ -589,16 +645,21 @@ int llc_conn_ac_send_rnr_rsp_f_set_1(struct sock *sk, struct sk_buff *skb) ...@@ -589,16 +645,21 @@ int llc_conn_ac_send_rnr_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_rnr_rsp(nskb, f_bit, llc->vR); llc_pdu_init_as_rnr_rsp(nskb, f_bit, llc->vR);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_send_rnr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_rnr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
...@@ -610,11 +671,16 @@ int llc_conn_ac_send_rnr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb) ...@@ -610,11 +671,16 @@ int llc_conn_ac_send_rnr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_rnr_rsp(nskb, f_bit, llc->vR); llc_pdu_init_as_rnr_rsp(nskb, f_bit, llc->vR);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_set_remote_busy(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_set_remote_busy(struct sock *sk, struct sk_buff *skb)
...@@ -631,70 +697,82 @@ int llc_conn_ac_set_remote_busy(struct sock *sk, struct sk_buff *skb) ...@@ -631,70 +697,82 @@ int llc_conn_ac_set_remote_busy(struct sock *sk, struct sk_buff *skb)
int llc_conn_ac_opt_send_rnr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_opt_send_rnr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap; struct llc_sap *sap = llc->sap;
u8 f_bit = 0;
nskb->dev = llc->dev; nskb->dev = llc->dev;
llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_rnr_rsp(nskb, f_bit, llc->vR); llc_pdu_init_as_rnr_rsp(nskb, 0, llc->vR);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_send_rr_cmd_p_set_1(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_rr_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
u8 p_bit = 1;
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap; struct llc_sap *sap = llc->sap;
nskb->dev = llc->dev; nskb->dev = llc->dev;
llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_CMD); llc->daddr.lsap, LLC_PDU_CMD);
llc_pdu_init_as_rr_cmd(nskb, p_bit, llc->vR); llc_pdu_init_as_rr_cmd(nskb, 1, llc->vR);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_send_ack_cmd_p_set_1(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_ack_cmd_p_set_1(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
u8 p_bit = 1;
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap; struct llc_sap *sap = llc->sap;
nskb->dev = llc->dev; nskb->dev = llc->dev;
llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_CMD); llc->daddr.lsap, LLC_PDU_CMD);
llc_pdu_init_as_rr_cmd(nskb, p_bit, llc->vR); llc_pdu_init_as_rr_cmd(nskb, 1, llc->vR);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_send_rr_rsp_f_set_1(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_rr_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
...@@ -706,16 +784,21 @@ int llc_conn_ac_send_rr_rsp_f_set_1(struct sock *sk, struct sk_buff *skb) ...@@ -706,16 +784,21 @@ int llc_conn_ac_send_rr_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_rr_rsp(nskb, f_bit, llc->vR); llc_pdu_init_as_rr_rsp(nskb, f_bit, llc->vR);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_send_ack_rsp_f_set_1(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_ack_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
...@@ -727,53 +810,66 @@ int llc_conn_ac_send_ack_rsp_f_set_1(struct sock *sk, struct sk_buff *skb) ...@@ -727,53 +810,66 @@ int llc_conn_ac_send_ack_rsp_f_set_1(struct sock *sk, struct sk_buff *skb)
llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_rr_rsp(nskb, f_bit, llc->vR); llc_pdu_init_as_rr_rsp(nskb, f_bit, llc->vR);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_send_rr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_rr_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap; struct llc_sap *sap = llc->sap;
u8 f_bit = 0;
nskb->dev = llc->dev; nskb->dev = llc->dev;
llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_rr_rsp(nskb, f_bit, llc->vR); llc_pdu_init_as_rr_rsp(nskb, 0, llc->vR);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_send_ack_xxx_x_set_0(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_ack_xxx_x_set_0(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap; struct llc_sap *sap = llc->sap;
u8 f_bit = 0;
nskb->dev = llc->dev; nskb->dev = llc->dev;
llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_rr_rsp(nskb, f_bit, llc->vR); llc_pdu_init_as_rr_rsp(nskb, 0, llc->vR);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
void llc_conn_set_p_flag(struct sock *sk, u8 value) void llc_conn_set_p_flag(struct sock *sk, u8 value)
...@@ -788,10 +884,9 @@ void llc_conn_set_p_flag(struct sock *sk, u8 value) ...@@ -788,10 +884,9 @@ void llc_conn_set_p_flag(struct sock *sk, u8 value)
int llc_conn_ac_send_sabme_cmd_p_set_x(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_sabme_cmd_p_set_x(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
u8 p_bit = 1;
if (nskb) { if (nskb) {
struct llc_sap *sap = llc->sap; struct llc_sap *sap = llc->sap;
...@@ -802,41 +897,49 @@ int llc_conn_ac_send_sabme_cmd_p_set_x(struct sock *sk, struct sk_buff *skb) ...@@ -802,41 +897,49 @@ int llc_conn_ac_send_sabme_cmd_p_set_x(struct sock *sk, struct sk_buff *skb)
nskb->dev = llc->dev; nskb->dev = llc->dev;
llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_CMD); llc->daddr.lsap, LLC_PDU_CMD);
llc_pdu_init_as_sabme_cmd(nskb, p_bit); llc_pdu_init_as_sabme_cmd(nskb, 1);
lan_hdrs_init(nskb, llc->dev->dev_addr, dmac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, dmac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
llc_conn_set_p_flag(sk, 1);
} }
llc_conn_set_p_flag(sk, p_bit); out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_send_ua_rsp_f_set_f_flag(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_ua_rsp_f_set_f_flag(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap; struct llc_sap *sap = llc->sap;
u8 f_bit = llc->f_flag;
nskb->dev = llc->dev; nskb->dev = llc->dev;
llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_ua_rsp(nskb, f_bit); llc_pdu_init_as_ua_rsp(nskb, llc->f_flag);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_send_ua_rsp_f_set_p(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_ua_rsp_f_set_p(struct sock *sk, struct sk_buff *skb)
{ {
u8 f_bit; u8 f_bit;
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
llc_pdu_decode_pf_bit(skb, &f_bit); llc_pdu_decode_pf_bit(skb, &f_bit);
...@@ -848,11 +951,16 @@ int llc_conn_ac_send_ua_rsp_f_set_p(struct sock *sk, struct sk_buff *skb) ...@@ -848,11 +951,16 @@ int llc_conn_ac_send_ua_rsp_f_set_p(struct sock *sk, struct sk_buff *skb)
llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_ua_rsp(nskb, f_bit); llc_pdu_init_as_ua_rsp(nskb, f_bit);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
int llc_conn_ac_set_s_flag_0(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_set_s_flag_0(struct sock *sk, struct sk_buff *skb)
...@@ -935,17 +1043,19 @@ int llc_conn_ac_rst_sendack_flag(struct sock *sk, struct sk_buff *skb) ...@@ -935,17 +1043,19 @@ int llc_conn_ac_rst_sendack_flag(struct sock *sk, struct sk_buff *skb)
*/ */
int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_i_rsp_f_set_ackpf(struct sock *sk, struct sk_buff *skb)
{ {
int rc;
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
u8 p_bit = llc->ack_pf;
struct llc_sap *sap = llc->sap; struct llc_sap *sap = llc->sap;
llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap, llc_pdu_header_init(skb, LLC_PDU_TYPE_I, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_i_cmd(skb, p_bit, llc->vS, llc->vR); llc_pdu_init_as_i_cmd(skb, llc->ack_pf, llc->vS, llc->vR);
lan_hdrs_init(skb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(skb, llc->dev->dev_addr, llc->daddr.mac);
llc_conn_send_pdu(sk, skb); if (!rc) {
llc_conn_ac_inc_vs_by_1(sk, skb); llc_conn_send_pdu(sk, skb);
return 0; llc_conn_ac_inc_vs_by_1(sk, skb);
}
return rc;
} }
/** /**
...@@ -983,23 +1093,27 @@ int llc_conn_ac_send_i_as_ack(struct sock *sk, struct sk_buff *skb) ...@@ -983,23 +1093,27 @@ int llc_conn_ac_send_i_as_ack(struct sock *sk, struct sk_buff *skb)
*/ */
int llc_conn_ac_send_rr_rsp_f_set_ackpf(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_send_rr_rsp_f_set_ackpf(struct sock *sk, struct sk_buff *skb)
{ {
int rc = 1; int rc = -ENOBUFS;
struct sk_buff *nskb = llc_alloc_frame(); struct sk_buff *nskb = llc_alloc_frame();
if (nskb) { if (nskb) {
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap; struct llc_sap *sap = llc->sap;
u8 f_bit = llc->ack_pf;
nskb->dev = llc->dev; nskb->dev = llc->dev;
llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_S, sap->laddr.lsap,
llc->daddr.lsap, LLC_PDU_RSP); llc->daddr.lsap, LLC_PDU_RSP);
llc_pdu_init_as_rr_rsp(nskb, f_bit, llc->vR); llc_pdu_init_as_rr_rsp(nskb, llc->ack_pf, llc->vR);
lan_hdrs_init(nskb, llc->dev->dev_addr, llc->daddr.mac); rc = llc_mac_hdr_init(nskb, llc->dev->dev_addr, llc->daddr.mac);
rc = 0; if (rc)
goto free;
llc_conn_send_pdu(sk, nskb); llc_conn_send_pdu(sk, nskb);
} }
out:
return rc; return rc;
free:
kfree_skb(nskb);
goto out;
} }
/** /**
...@@ -1193,7 +1307,6 @@ int llc_conn_ac_upd_nr_received(struct sock *sk, struct sk_buff *skb) ...@@ -1193,7 +1307,6 @@ int llc_conn_ac_upd_nr_received(struct sock *sk, struct sk_buff *skb)
{ {
int acked; int acked;
u16 unacked = 0; u16 unacked = 0;
u8 fbit;
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
...@@ -1215,8 +1328,10 @@ int llc_conn_ac_upd_nr_received(struct sock *sk, struct sk_buff *skb) ...@@ -1215,8 +1328,10 @@ int llc_conn_ac_upd_nr_received(struct sock *sk, struct sk_buff *skb)
mod_timer(&llc->ack_timer.timer, mod_timer(&llc->ack_timer.timer,
jiffies + llc->ack_timer.expire * HZ); jiffies + llc->ack_timer.expire * HZ);
} else if (llc->failed_data_req) { } else if (llc->failed_data_req) {
llc_pdu_decode_pf_bit(skb, &fbit); u8 f_bit;
if (fbit == 1) {
llc_pdu_decode_pf_bit(skb, &f_bit);
if (f_bit == 1) {
llc->failed_data_req = 0; llc->failed_data_req = 0;
llc_conn_ac_data_confirm(sk, skb); llc_conn_ac_data_confirm(sk, skb);
} }
......
...@@ -11,21 +11,16 @@ ...@@ -11,21 +11,16 @@
* *
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*/ */
#include <linux/netdevice.h>
#include <linux/interrupt.h>
#include <linux/init.h> #include <linux/init.h>
#include <net/llc_if.h>
#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 <linux/tcp.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>
#include <net/llc_c_st.h> #include <net/llc_c_st.h>
#include <net/llc_mac.h>
#include <net/llc_pdu.h> #include <net/llc_pdu.h>
#include <net/llc_s_ev.h>
#if 0 #if 0
#define dprintk(args...) printk(KERN_DEBUG args) #define dprintk(args...) printk(KERN_DEBUG args)
......
/*
* llc_core.c - Minimum needed routines for sap handling and module init/exit
*
* Copyright (c) 1997 by Procom Technology, Inc.
* 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* This program can be redistributed or modified under the terms of the
* GNU General Public License as published by the Free Software Foundation.
* This program is distributed without any warranty or implied warranty
* of merchantability or fitness for a particular purpose.
*
* See the GNU General Public License for more details.
*/
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/if_ether.h>
#include <linux/netdevice.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <net/llc.h>
LIST_HEAD(llc_sap_list);
rwlock_t llc_sap_list_lock = RW_LOCK_UNLOCKED;
unsigned char llc_station_mac_sa[ETH_ALEN];
/**
* llc_sap_alloc - allocates and initializes sap.
*
* Allocates and initializes sap.
*/
struct llc_sap *llc_sap_alloc(void)
{
struct llc_sap *sap = kmalloc(sizeof(*sap), GFP_ATOMIC);
if (sap) {
memset(sap, 0, sizeof(*sap));
sap->state = LLC_SAP_STATE_ACTIVE;
memcpy(sap->laddr.mac, llc_station_mac_sa, ETH_ALEN);
rwlock_init(&sap->sk_list.lock);
}
return sap;
}
/**
* llc_add_sap - add sap to station list
* @sap: Address of the sap
*
* Adds a sap to the LLC's station sap list.
*/
void llc_add_sap(struct llc_sap *sap)
{
write_lock_bh(&llc_sap_list_lock);
list_add_tail(&sap->node, &llc_sap_list);
write_unlock_bh(&llc_sap_list_lock);
}
/**
* llc_del_sap - del sap from station list
* @sap: Address of the sap
*
* Removes a sap to the LLC's station sap list.
*/
void llc_del_sap(struct llc_sap *sap)
{
write_lock_bh(&llc_sap_list_lock);
list_del(&sap->node);
write_unlock_bh(&llc_sap_list_lock);
}
/**
* llc_sap_find - searchs a SAP in station
* @sap_value: sap to be found
*
* Searchs for a sap in the sap list of the LLC's station upon the sap ID.
* Returns the sap or %NULL if not found.
*/
struct llc_sap *llc_sap_find(unsigned char sap_value)
{
struct llc_sap* sap = NULL;
struct list_head *entry;
read_lock_bh(&llc_sap_list_lock);
list_for_each(entry, &llc_sap_list) {
sap = list_entry(entry, struct llc_sap, node);
if (sap->laddr.lsap == sap_value)
break;
}
if (entry == &llc_sap_list) /* not found */
sap = NULL;
read_unlock_bh(&llc_sap_list_lock);
return sap;
}
/**
* llc_sap_open - open interface to the upper layers.
* @lsap: SAP number.
* @func: rcv func for datalink protos
*
* Interface function to upper layer. Each one who wants to get a SAP
* (for example NetBEUI) should call this function. Returns the opened
* SAP for success, NULL for failure.
*/
struct llc_sap *llc_sap_open(unsigned char lsap,
int (*func)(struct sk_buff *skb,
struct net_device *dev,
struct packet_type *pt))
{
struct llc_sap *sap = llc_sap_find(lsap);
if (sap) { /* SAP already exists */
sap = NULL;
goto out;
}
sap = llc_sap_alloc();
if (!sap)
goto out;
sap->laddr.lsap = lsap;
sap->rcv_func = func;
llc_add_sap(sap);
out:
return sap;
}
/**
* llc_sap_close - close interface for upper layers.
* @sap: SAP to be closed.
*
* Close interface function to upper layer. Each one who wants to
* close an open SAP (for example NetBEUI) should call this function.
* Removes this sap from the list of saps in the station and then
* frees the memory for this sap.
*/
void llc_sap_close(struct llc_sap *sap)
{
WARN_ON(!hlist_empty(&sap->sk_list.list));
llc_del_sap(sap);
kfree(sap);
}
static struct packet_type llc_packet_type = {
.type = __constant_htons(ETH_P_802_2),
.func = llc_rcv,
.data = (void *)1,
};
static struct packet_type llc_tr_packet_type = {
.type = __constant_htons(ETH_P_TR_802_2),
.func = llc_rcv,
.data = (void *)1,
};
static int __init llc_init(void)
{
if (dev_base->next)
memcpy(llc_station_mac_sa, dev_base->next->dev_addr, ETH_ALEN);
else
memset(llc_station_mac_sa, 0, ETH_ALEN);
dev_add_pack(&llc_packet_type);
dev_add_pack(&llc_tr_packet_type);
return 0;
}
static void __exit llc_exit(void)
{
dev_remove_pack(&llc_packet_type);
dev_remove_pack(&llc_tr_packet_type);
}
module_init(llc_init);
module_exit(llc_exit);
EXPORT_SYMBOL(llc_station_mac_sa);
EXPORT_SYMBOL(llc_sap_list);
EXPORT_SYMBOL(llc_sap_list_lock);
EXPORT_SYMBOL(llc_sap_find);
EXPORT_SYMBOL(llc_sap_open);
EXPORT_SYMBOL(llc_sap_close);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Procom 1997, Jay Schullist 2001, Arnaldo C. Melo 2001-2003");
MODULE_DESCRIPTION("LLC IEEE 802.2 core support");
/*
* llc_evnt.c - LLC station component event match functions
* Description :
* Functions in this module are implementation of station component events.
* Details of events can be found in IEEE-802.2 standard document.
* All functions have one station and one event as input argument. All of
* them return 0 On success and 1 otherwise.
*
* Copyright (c) 1997 by Procom Technology, Inc.
* 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* This program can be redistributed or modified under the terms of the
* GNU General Public License as published by the Free Software Foundation.
* This program is distributed without any warranty or implied warranty
* of merchantability or fitness for a particular purpose.
*
* See the GNU General Public License for more details.
*/
#include <linux/socket.h>
#include <net/sock.h>
#include <net/llc_if.h>
#include <net/llc_main.h>
#include <net/llc_evnt.h>
#include <net/llc_pdu.h>
int llc_stat_ev_enable_with_dup_addr_check(struct llc_station *station,
struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
return ev->type == LLC_STATION_EV_TYPE_SIMPLE &&
ev->prim_type ==
LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK ? 0 : 1;
}
int llc_stat_ev_enable_without_dup_addr_check(struct llc_station *station,
struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
return ev->type == LLC_STATION_EV_TYPE_SIMPLE &&
ev->prim_type ==
LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK ? 0 : 1;
}
int llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry(struct llc_station *station,
struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
return ev->type == LLC_STATION_EV_TYPE_ACK_TMR &&
station->retry_count < station->maximum_retry ? 0 : 1;
}
int llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry(struct llc_station *station,
struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
return ev->type == LLC_STATION_EV_TYPE_ACK_TMR &&
station->retry_count == station->maximum_retry ? 0 : 1;
}
int llc_stat_ev_rx_null_dsap_xid_c(struct llc_station *station,
struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
return ev->type == LLC_STATION_EV_TYPE_PDU &&
LLC_PDU_IS_CMD(pdu) && /* command PDU */
LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */
LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID &&
!pdu->dsap ? 0 : 1; /* NULL DSAP value */
}
int llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq(struct llc_station *station,
struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
return ev->type == LLC_STATION_EV_TYPE_PDU &&
LLC_PDU_IS_RSP(pdu) && /* response PDU */
LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */
LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID &&
!pdu->dsap && /* NULL DSAP value */
!station->xid_r_count ? 0 : 1;
}
int llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq(struct llc_station *station,
struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
return ev->type == LLC_STATION_EV_TYPE_PDU &&
LLC_PDU_IS_RSP(pdu) && /* response PDU */
LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */
LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID &&
!pdu->dsap && /* NULL DSAP value */
station->xid_r_count == 1 ? 0 : 1;
}
int llc_stat_ev_rx_null_dsap_test_c(struct llc_station *station,
struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
return ev->type == LLC_STATION_EV_TYPE_PDU &&
LLC_PDU_IS_CMD(pdu) && /* command PDU */
LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */
LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST &&
!pdu->dsap ? 0 : 1; /* NULL DSAP */
}
int llc_stat_ev_disable_req(struct llc_station *station, struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
return ev->type == LLC_STATION_EV_TYPE_PRIM &&
ev->prim == LLC_DISABLE_PRIM &&
ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1;
}
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include <net/llc_c_ev.h> #include <net/llc_c_ev.h>
#include <net/llc_c_ac.h> #include <net/llc_c_ac.h>
#include <net/llc_c_st.h> #include <net/llc_c_st.h>
#include <net/llc_main.h>
u8 llc_mac_null_var[IFHWADDRLEN]; u8 llc_mac_null_var[IFHWADDRLEN];
......
/* /*
* llc_mac.c - Manages interface between LLC and MAC * llc_input.c - Minimal input path for LLC
* *
* Copyright (c) 1997 by Procom Technology, Inc. * Copyright (c) 1997 by Procom Technology, Inc.
* 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> * 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
...@@ -12,15 +12,9 @@ ...@@ -12,15 +12,9 @@
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*/ */
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if_arp.h> #include <net/llc.h>
#include <linux/if_tr.h>
#include <linux/rtnetlink.h>
#include <net/llc_mac.h>
#include <net/llc_pdu.h> #include <net/llc_pdu.h>
#include <net/llc_sap.h> #include <net/llc_sap.h>
#include <net/llc_main.h>
#include <net/llc_evnt.h>
#include <linux/trdevice.h>
#if 0 #if 0
#define dprintk(args...) printk(KERN_DEBUG args) #define dprintk(args...) printk(KERN_DEBUG args)
...@@ -28,14 +22,19 @@ ...@@ -28,14 +22,19 @@
#define dprintk(args...) #define dprintk(args...)
#endif #endif
static int fix_up_incoming_skb(struct sk_buff *skb); /*
static void llc_station_rcv(struct sk_buff *skb); * Packet handler for the station, registerable because in the minimal
* LLC core that is taking shape only the very minimal subset of LLC that
* is needed for things like IPX, Appletalk, etc will stay, with all the
* rest in the llc1 and llc2 modules.
*/
static void (*llc_station_handler)(struct sk_buff *skb);
/* /*
* Packet handlers for LLC_DEST_SAP and LLC_DEST_CONN. * Packet handlers for LLC_DEST_SAP and LLC_DEST_CONN.
*/ */
static void (*llc_type_handlers[2])(struct llc_sap *sap, static void (*llc_type_handlers[2])(struct llc_sap *sap,
struct sk_buff *skb); struct sk_buff *skb);
void llc_add_pack(int type, void (*handler)(struct llc_sap *sap, void llc_add_pack(int type, void (*handler)(struct llc_sap *sap,
struct sk_buff *skb)) struct sk_buff *skb))
...@@ -50,6 +49,11 @@ void llc_remove_pack(int type) ...@@ -50,6 +49,11 @@ void llc_remove_pack(int type)
llc_type_handlers[type] = NULL; llc_type_handlers[type] = NULL;
} }
void llc_set_station_handler(void (*handler)(struct sk_buff *skb))
{
llc_station_handler = handler;
}
/** /**
* llc_pdu_type - returns which LLC component must handle for PDU * llc_pdu_type - returns which LLC component must handle for PDU
* @skb: input skb * @skb: input skb
...@@ -83,6 +87,38 @@ static __inline__ int llc_pdu_type(struct sk_buff *skb) ...@@ -83,6 +87,38 @@ static __inline__ int llc_pdu_type(struct sk_buff *skb)
return type; return type;
} }
/**
* llc_fixup_skb - initializes skb pointers
* @skb: This argument points to incoming skb
*
* Initializes internal skb pointer to start of network layer by deriving
* length of LLC header; finds length of LLC control field in LLC header
* by looking at the two lowest-order bits of the first control field
* byte; field is either 3 or 4 bytes long.
*/
static inline int llc_fixup_skb(struct sk_buff *skb)
{
u8 llc_len = 2;
struct llc_pdu_sn *pdu;
if (!pskb_may_pull(skb, sizeof(*pdu)))
return 0;
pdu = (struct llc_pdu_sn *)skb->data;
if ((pdu->ctrl_1 & LLC_PDU_TYPE_MASK) == LLC_PDU_TYPE_U)
llc_len = 1;
llc_len += 2;
skb->h.raw += llc_len;
skb_pull(skb, llc_len);
if (skb->protocol == htons(ETH_P_802_2)) {
u16 pdulen = ((struct ethhdr *)skb->mac.raw)->h_proto,
data_size = ntohs(pdulen) - llc_len;
skb_trim(skb, data_size);
}
return 1;
}
/** /**
* llc_rcv - 802.2 entry point from net lower layers * llc_rcv - 802.2 entry point from net lower layers
* @skb: received pdu * @skb: received pdu
...@@ -106,23 +142,20 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -106,23 +142,20 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
* When the interface is in promisc. mode, drop all the crap that it * When the interface is in promisc. mode, drop all the crap that it
* receives, do not try to analyse it. * receives, do not try to analyse it.
*/ */
if (skb->pkt_type == PACKET_OTHERHOST) { if (unlikely(skb->pkt_type == PACKET_OTHERHOST)) {
dprintk("%s: PACKET_OTHERHOST\n", __FUNCTION__); dprintk("%s: PACKET_OTHERHOST\n", __FUNCTION__);
goto drop; goto drop;
} }
skb = skb_share_check(skb, GFP_ATOMIC); skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb) if (unlikely(!skb))
goto out; goto out;
if (!fix_up_incoming_skb(skb)) if (unlikely(!llc_fixup_skb(skb)))
goto drop; goto drop;
pdu = llc_pdu_sn_hdr(skb); pdu = llc_pdu_sn_hdr(skb);
if (!pdu->dsap) { /* NULL DSAP, refer to station */ if (unlikely(!pdu->dsap)) /* NULL DSAP, refer to station */
dprintk("%s: calling llc_station_rcv!\n", __FUNCTION__); goto handle_station;
llc_station_rcv(skb);
goto out;
}
sap = llc_sap_find(pdu->dsap); sap = llc_sap_find(pdu->dsap);
if (!sap) {/* unknown SAP */ if (unlikely(!sap)) {/* unknown SAP */
dprintk("%s: llc_sap_find(%02X) failed!\n", __FUNCTION__, dprintk("%s: llc_sap_find(%02X) failed!\n", __FUNCTION__,
pdu->dsap); pdu->dsap);
goto drop; goto drop;
...@@ -144,109 +177,13 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev, ...@@ -144,109 +177,13 @@ int llc_rcv(struct sk_buff *skb, struct net_device *dev,
drop: drop:
kfree_skb(skb); kfree_skb(skb);
goto out; goto out;
} handle_station:
if (!llc_station_handler)
/** goto drop;
* fix_up_incoming_skb - initializes skb pointers llc_station_handler(skb);
* @skb: This argument points to incoming skb goto out;
*
* Initializes internal skb pointer to start of network layer by deriving
* length of LLC header; finds length of LLC control field in LLC header
* by looking at the two lowest-order bits of the first control field
* byte; field is either 3 or 4 bytes long.
*/
static int fix_up_incoming_skb(struct sk_buff *skb)
{
u8 llc_len = 2;
struct llc_pdu_sn *pdu;
if (!pskb_may_pull(skb, sizeof(*pdu)))
return 0;
pdu = (struct llc_pdu_sn *)skb->data;
if ((pdu->ctrl_1 & LLC_PDU_TYPE_MASK) == LLC_PDU_TYPE_U)
llc_len = 1;
llc_len += 2;
skb->h.raw += llc_len;
skb_pull(skb, llc_len);
if (skb->protocol == htons(ETH_P_802_2)) {
u16 pdulen = ((struct ethhdr *)skb->mac.raw)->h_proto,
data_size = ntohs(pdulen) - llc_len;
skb_trim(skb, data_size);
}
return 1;
}
/*
* llc_station_rcv - send received pdu to the station state machine
* @skb: received frame.
*
* Sends data unit to station state machine.
*/
static void llc_station_rcv(struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
ev->type = LLC_STATION_EV_TYPE_PDU;
ev->reason = 0;
llc_station_state_process(&llc_main_station, skb);
}
/**
* lan_hdrs_init - fills MAC header fields
* @skb: Address of the frame to initialize its MAC header
* @sa: The MAC source address
* @da: The MAC destination address
*
* Fills MAC header fields, depending on MAC type. Returns 0, If MAC type
* is a valid type and initialization completes correctly 1, otherwise.
*/
u16 lan_hdrs_init(struct sk_buff *skb, u8 *sa, u8 *da)
{
u16 rc = 0;
switch (skb->dev->type) {
#ifdef CONFIG_TR
case ARPHRD_IEEE802_TR: {
struct trh_hdr *trh;
struct net_device *dev = skb->dev;
trh = (struct trh_hdr *)skb_push(skb, sizeof(*trh));
trh->ac = AC;
trh->fc = LLC_FRAME;
if (sa)
memcpy(trh->saddr, sa, dev->addr_len);
else
memset(trh->saddr, 0, dev->addr_len);
if (da) {
memcpy(trh->daddr, da, dev->addr_len);
tr_source_route(skb, trh, dev);
}
skb->mac.raw = skb->data;
break;
}
#endif
case ARPHRD_ETHER:
case ARPHRD_LOOPBACK: {
unsigned short len = skb->len;
struct ethhdr *eth;
skb->mac.raw = skb_push(skb, sizeof(*eth));
eth = (struct ethhdr *)skb->mac.raw;
eth->h_proto = htons(len);
memcpy(eth->h_dest, da, ETH_ALEN);
memcpy(eth->h_source, sa, ETH_ALEN);
break;
}
default:
printk(KERN_WARNING "Unknown DEVICE type : %d\n",
skb->dev->type);
rc = 1;
}
return rc;
} }
EXPORT_SYMBOL(llc_add_pack); EXPORT_SYMBOL(llc_add_pack);
EXPORT_SYMBOL(llc_remove_pack); EXPORT_SYMBOL(llc_remove_pack);
EXPORT_SYMBOL(lan_hdrs_init); EXPORT_SYMBOL(llc_set_station_handler);
/*
* llc_main.c - This module contains main functions to manage station, saps
* and connections of the LLC.
*
* Copyright (c) 1997 by Procom Technology, Inc.
* 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* This program can be redistributed or modified under the terms of the
* GNU General Public License as published by the Free Software Foundation.
* This program is distributed without any warranty or implied warranty
* of merchantability or fitness for a particular purpose.
*
* See the GNU General Public License for more details.
*/
#include <linux/config.h>
#include <linux/init.h>
#include <linux/module.h>
#include <net/llc_sap.h>
#include <net/llc_conn.h>
#include <net/llc_main.h>
#include <net/llc_evnt.h>
#include <net/llc_actn.h>
#include <net/llc_stat.h>
#include <net/llc_c_ac.h>
#include <net/llc_s_ac.h>
#include <net/llc_c_ev.h>
#include <net/llc_c_st.h>
#include <net/llc_s_ev.h>
#include <net/llc_s_st.h>
#include <net/llc_mac.h>
#include <net/llc_proc.h>
/* static function prototypes */
static void llc_station_service_events(struct llc_station *station);
static void llc_station_free_ev(struct llc_station *station,
struct sk_buff *skb);
static void llc_station_send_pdus(struct llc_station *station);
static u16 llc_station_next_state(struct llc_station *station,
struct sk_buff *skb);
static u16 llc_exec_station_trans_actions(struct llc_station *station,
struct llc_station_state_trans *trans,
struct sk_buff *skb);
static struct llc_station_state_trans *
llc_find_station_trans(struct llc_station *station,
struct sk_buff *skb);
struct llc_station llc_main_station; /* only one of its kind */
/**
* llc_sap_save - add sap to station list
* @sap: Address of the sap
*
* Adds a sap to the LLC's station sap list.
*/
void llc_sap_save(struct llc_sap *sap)
{
write_lock_bh(&llc_main_station.sap_list.lock);
list_add_tail(&sap->node, &llc_main_station.sap_list.list);
write_unlock_bh(&llc_main_station.sap_list.lock);
}
/**
* llc_sap_find - searchs a SAP in station
* @sap_value: sap to be found
*
* Searchs for a sap in the sap list of the LLC's station upon the sap ID.
* Returns the sap or %NULL if not found.
*/
struct llc_sap *llc_sap_find(u8 sap_value)
{
struct llc_sap* sap = NULL;
struct list_head *entry;
read_lock_bh(&llc_main_station.sap_list.lock);
list_for_each(entry, &llc_main_station.sap_list.list) {
sap = list_entry(entry, struct llc_sap, node);
if (sap->laddr.lsap == sap_value)
break;
}
if (entry == &llc_main_station.sap_list.list) /* not found */
sap = NULL;
read_unlock_bh(&llc_main_station.sap_list.lock);
return sap;
}
/**
* llc_station_state_process: queue event and try to process queue.
* @station: Address of the station
* @skb: Address of the event
*
* Queues an event (on the station event queue) for handling by the
* station state machine and attempts to process any queued-up events.
*/
void llc_station_state_process(struct llc_station *station, struct sk_buff *skb)
{
spin_lock_bh(&station->ev_q.lock);
skb_queue_tail(&station->ev_q.list, skb);
llc_station_service_events(station);
spin_unlock_bh(&station->ev_q.lock);
}
/**
* llc_station_send_pdu - queues PDU to send
* @station: Address of the station
* @skb: Address of the PDU
*
* Queues a PDU to send to the MAC layer.
*/
void llc_station_send_pdu(struct llc_station *station, struct sk_buff *skb)
{
skb_queue_tail(&station->mac_pdu_q, skb);
llc_station_send_pdus(station);
}
/**
* llc_station_send_pdus - tries to send queued PDUs
* @station: Address of the station
*
* Tries to send any PDUs queued in the station mac_pdu_q to the MAC
* layer.
*/
static void llc_station_send_pdus(struct llc_station *station)
{
struct sk_buff *skb;
while ((skb = skb_dequeue(&station->mac_pdu_q)) != NULL)
if (dev_queue_xmit(skb))
break;
}
/**
* llc_station_free_ev - frees an event
* @station: Address of the station
* @skb: Address of the event
*
* Frees an event.
*/
static void llc_station_free_ev(struct llc_station *station,
struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
if (ev->type == LLC_STATION_EV_TYPE_PDU)
kfree_skb(skb);
}
/**
* llc_station_service_events - service events in the queue
* @station: Address of the station
*
* Get an event from the station event queue (if any); attempt to service
* the event; if event serviced, get the next event (if any) on the event
* queue; if event not service, re-queue the event on the event queue and
* attempt to service the next event; when serviced all events in queue,
* finished; if don't transition to different state, just service all
* events once; if transition to new state, service all events again.
* Caller must hold station->ev_q.lock.
*/
static void llc_station_service_events(struct llc_station *station)
{
struct sk_buff *skb;
while ((skb = skb_dequeue(&station->ev_q.list)) != NULL)
llc_station_next_state(station, skb);
}
/**
* llc_station_next_state - processes event and goes to the next state
* @station: Address of the station
* @skb: Address of the event
*
* Processes an event, executes any transitions related to that event and
* updates the state of the station.
*/
static u16 llc_station_next_state(struct llc_station *station,
struct sk_buff *skb)
{
u16 rc = 1;
struct llc_station_state_trans *trans;
if (station->state > LLC_NBR_STATION_STATES)
goto out;
trans = llc_find_station_trans(station, skb);
if (trans) {
/* got the state to which we next transition; perform the
* actions associated with this transition before actually
* transitioning to the next state
*/
rc = llc_exec_station_trans_actions(station, trans, skb);
if (!rc)
/* transition station to next state if all actions
* execute successfully; done; wait for next event
*/
station->state = trans->next_state;
} else
/* event not recognized in current state; re-queue it for
* processing again at a later time; return failure
*/
rc = 0;
out:
llc_station_free_ev(station, skb);
return rc;
}
/**
* llc_find_station_trans - finds transition for this event
* @station: Address of the station
* @skb: Address of the event
*
* Search thru events of the current state of the station until list
* exhausted or it's obvious that the event is not valid for the current
* state. Returns the address of the transition if cound, %NULL otherwise.
*/
static struct llc_station_state_trans *
llc_find_station_trans(struct llc_station *station,
struct sk_buff *skb)
{
int i = 0;
struct llc_station_state_trans *rc = NULL;
struct llc_station_state_trans **next_trans;
struct llc_station_state *curr_state =
&llc_station_state_table[station->state - 1];
for (next_trans = curr_state->transitions; next_trans[i]->ev; i++)
if (!next_trans[i]->ev(station, skb)) {
rc = next_trans[i];
break;
}
return rc;
}
/**
* llc_exec_station_trans_actions - executes actions for transition
* @station: Address of the station
* @trans: Address of the transition
* @skb: Address of the event that caused the transition
*
* Executes actions of a transition of the station state machine. Returns
* 0 if all actions complete successfully, nonzero otherwise.
*/
static u16 llc_exec_station_trans_actions(struct llc_station *station,
struct llc_station_state_trans *trans,
struct sk_buff *skb)
{
u16 rc = 0;
llc_station_action_t *next_action = trans->ev_actions;
for (; next_action && *next_action; next_action++)
if ((*next_action)(station, skb))
rc = 1;
return rc;
}
/**
* llc_alloc_frame - allocates sk_buff for frame
*
* Allocates an sk_buff for frame and initializes sk_buff fields.
* Returns allocated skb or %NULL when out of memory.
*/
struct sk_buff *llc_alloc_frame(void)
{
struct sk_buff *skb = alloc_skb(128, GFP_ATOMIC);
if (skb) {
skb_reserve(skb, 50);
skb->nh.raw = skb->h.raw = skb->data;
skb->protocol = htons(ETH_P_802_2);
skb->dev = dev_base->next;
skb->mac.raw = skb->head;
}
return skb;
}
static struct packet_type llc_packet_type = {
.type = __constant_htons(ETH_P_802_2),
.func = llc_rcv,
.data = (void *)1,
};
static struct packet_type llc_tr_packet_type = {
.type = __constant_htons(ETH_P_TR_802_2),
.func = llc_rcv,
.data = (void *)1,
};
static char llc_error_msg[] __initdata =
KERN_ERR "LLC install NOT successful.\n";
static int __init llc_init(void)
{
u16 rc = 0;
struct sk_buff *skb;
struct llc_station_state_ev *ev;
INIT_LIST_HEAD(&llc_main_station.sap_list.list);
rwlock_init(&llc_main_station.sap_list.lock);
skb_queue_head_init(&llc_main_station.mac_pdu_q);
skb_queue_head_init(&llc_main_station.ev_q.list);
spin_lock_init(&llc_main_station.ev_q.lock);
init_timer(&llc_main_station.ack_timer);
llc_main_station.ack_timer.data = (unsigned long)&llc_main_station;
llc_main_station.ack_timer.function = llc_station_ack_tmr_cb;
skb = alloc_skb(0, GFP_ATOMIC);
if (!skb)
goto err;
ev = llc_station_ev(skb);
memset(ev, 0, sizeof(*ev));
if (dev_base->next)
memcpy(llc_main_station.mac_sa,
dev_base->next->dev_addr, ETH_ALEN);
else
memset(llc_main_station.mac_sa, 0, ETH_ALEN);
llc_main_station.ack_timer.expires = jiffies + 3 * HZ;
llc_main_station.maximum_retry = 1;
llc_main_station.state = LLC_STATION_STATE_DOWN;
ev->type = LLC_STATION_EV_TYPE_SIMPLE;
ev->prim_type = LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK;
rc = llc_station_next_state(&llc_main_station, skb);
dev_add_pack(&llc_packet_type);
dev_add_pack(&llc_tr_packet_type);
out:
return rc;
err:
printk(llc_error_msg);
rc = 1;
goto out;
}
static void __exit llc_exit(void)
{
dev_remove_pack(&llc_packet_type);
dev_remove_pack(&llc_tr_packet_type);
}
module_init(llc_init);
module_exit(llc_exit);
EXPORT_SYMBOL(llc_sap_find);
EXPORT_SYMBOL(llc_alloc_frame);
EXPORT_SYMBOL(llc_main_station);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Procom 1997, Jay Schullist 2001, Arnaldo C. Melo 2001-2003");
MODULE_DESCRIPTION("LLC IEEE 802.2 extended support");
MODULE_ALIAS_NETPROTO(PF_LLC);
/*
* llc_output.c - LLC minimal output path
*
* Copyright (c) 1997 by Procom Technology, Inc.
* 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* This program can be redistributed or modified under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation.
* This program is distributed without any warranty or implied warranty
* of merchantability or fitness for a particular purpose.
*
* See the GNU General Public License version 2 for more details.
*/
#include <linux/if_arp.h>
#include <linux/if_tr.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <net/llc.h>
#include <net/llc_pdu.h>
/**
* llc_mac_hdr_init - fills MAC header fields
* @skb: Address of the frame to initialize its MAC header
* @sa: The MAC source address
* @da: The MAC destination address
*
* Fills MAC header fields, depending on MAC type. Returns 0, If MAC type
* is a valid type and initialization completes correctly 1, otherwise.
*/
int llc_mac_hdr_init(struct sk_buff *skb, unsigned char *sa, unsigned char *da)
{
int rc = 0;
switch (skb->dev->type) {
#ifdef CONFIG_TR
case ARPHRD_IEEE802_TR: {
struct net_device *dev = skb->dev;
struct trh_hdr *trh;
trh = (struct trh_hdr *)skb_push(skb, sizeof(*trh));
trh->ac = AC;
trh->fc = LLC_FRAME;
if (sa)
memcpy(trh->saddr, sa, dev->addr_len);
else
memset(trh->saddr, 0, dev->addr_len);
if (da) {
memcpy(trh->daddr, da, dev->addr_len);
tr_source_route(skb, trh, dev);
}
skb->mac.raw = skb->data;
break;
}
#endif
case ARPHRD_ETHER:
case ARPHRD_LOOPBACK: {
unsigned short len = skb->len;
struct ethhdr *eth;
skb->mac.raw = skb_push(skb, sizeof(*eth));
eth = (struct ethhdr *)skb->mac.raw;
eth->h_proto = htons(len);
memcpy(eth->h_dest, da, ETH_ALEN);
memcpy(eth->h_source, sa, ETH_ALEN);
break;
}
default:
printk(KERN_WARNING "device type not supported: %d\n",
skb->dev->type);
rc = -EINVAL;
}
return rc;
}
/**
* llc_build_and_send_ui_pkt - unitdata request interface for upper layers
* @sap: sap to use
* @skb: packet to send
* @dmac: destination mac address
* @dsap: destination sap
*
* Upper layers calls this function when upper layer wants to send data
* using connection-less mode communication (UI pdu).
*
* Accept data frame from network layer to be sent using connection-
* less mode communication; timeout/retries handled by network layer;
* package primitive as an event and send to SAP event handler
*/
int llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb,
unsigned char *dmac, unsigned char dsap)
{
int rc;
llc_pdu_header_init(skb, LLC_PDU_TYPE_U, sap->laddr.lsap,
dsap, LLC_PDU_CMD);
llc_pdu_init_as_ui_cmd(skb);
rc = llc_mac_hdr_init(skb, skb->dev->dev_addr, dmac);
if (!rc)
rc = dev_queue_xmit(skb);
return rc;
}
EXPORT_SYMBOL(llc_mac_hdr_init);
EXPORT_SYMBOL(llc_build_and_send_ui_pkt);
#ifndef LLC_OUTPUT_H
#define LLC_OUTPUT_H
/*
* Copyright (c) 1997 by Procom Technology, Inc.
* 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* This program can be redistributed or modified under the terms of the
* GNU General Public License version 2 as published by the Free Software
* Foundation.
* This program is distributed without any warranty or implied warranty
* of merchantability or fitness for a particular purpose.
*
* See the GNU General Public License version 2 for more details.
*/
struct sk_buff;
int llc_mac_hdr_init(struct sk_buff *skb, unsigned char *sa, unsigned char *da);
#endif /* LLC_OUTPUT_H */
...@@ -11,11 +11,9 @@ ...@@ -11,11 +11,9 @@
* *
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*/ */
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if_tr.h>
#include <net/llc_pdu.h> #include <net/llc_pdu.h>
#include <net/llc_if.h>
#include <net/llc_main.h>
static void llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type); static void llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type);
static u8 llc_pdu_get_pf_bit(struct llc_pdu_sn *pdu); static u8 llc_pdu_get_pf_bit(struct llc_pdu_sn *pdu);
......
...@@ -20,13 +20,11 @@ ...@@ -20,13 +20,11 @@
#include <linux/errno.h> #include <linux/errno.h>
#include <linux/seq_file.h> #include <linux/seq_file.h>
#include <net/sock.h> #include <net/sock.h>
#include <net/llc.h>
#include <net/llc_c_ac.h> #include <net/llc_c_ac.h>
#include <net/llc_c_ev.h> #include <net/llc_c_ev.h>
#include <net/llc_c_st.h> #include <net/llc_c_st.h>
#include <net/llc_conn.h> #include <net/llc_conn.h>
#include <net/llc_mac.h>
#include <net/llc_main.h>
#include <net/llc_sap.h>
static void llc_ui_format_mac(struct seq_file *seq, unsigned char *mac) static void llc_ui_format_mac(struct seq_file *seq, unsigned char *mac)
{ {
...@@ -41,7 +39,7 @@ static struct sock *llc_get_sk_idx(loff_t pos) ...@@ -41,7 +39,7 @@ static struct sock *llc_get_sk_idx(loff_t pos)
struct hlist_node *node; struct hlist_node *node;
struct sock *sk = NULL; struct sock *sk = NULL;
list_for_each(sap_entry, &llc_main_station.sap_list.list) { list_for_each(sap_entry, &llc_sap_list) {
sap = list_entry(sap_entry, struct llc_sap, node); sap = list_entry(sap_entry, struct llc_sap, node);
read_lock_bh(&sap->sk_list.lock); read_lock_bh(&sap->sk_list.lock);
...@@ -66,7 +64,7 @@ static void *llc_seq_start(struct seq_file *seq, loff_t *pos) ...@@ -66,7 +64,7 @@ static void *llc_seq_start(struct seq_file *seq, loff_t *pos)
{ {
loff_t l = *pos; loff_t l = *pos;
read_lock_bh(&llc_main_station.sap_list.lock); read_lock_bh(&llc_sap_list_lock);
return l ? llc_get_sk_idx(--l) : SEQ_START_TOKEN; return l ? llc_get_sk_idx(--l) : SEQ_START_TOKEN;
} }
...@@ -92,7 +90,7 @@ static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos) ...@@ -92,7 +90,7 @@ static void *llc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
read_unlock_bh(&sap->sk_list.lock); read_unlock_bh(&sap->sk_list.lock);
sk = NULL; sk = NULL;
for (;;) { for (;;) {
if (sap->node.next == &llc_main_station.sap_list.list) if (sap->node.next == &llc_sap_list)
break; break;
sap = list_entry(sap->node.next, struct llc_sap, node); sap = list_entry(sap->node.next, struct llc_sap, node);
read_lock_bh(&sap->sk_list.lock); read_lock_bh(&sap->sk_list.lock);
...@@ -115,7 +113,7 @@ static void llc_seq_stop(struct seq_file *seq, void *v) ...@@ -115,7 +113,7 @@ static void llc_seq_stop(struct seq_file *seq, void *v)
read_unlock_bh(&sap->sk_list.lock); read_unlock_bh(&sap->sk_list.lock);
} }
read_unlock_bh(&llc_main_station.sap_list.lock); read_unlock_bh(&llc_sap_list_lock);
} }
static int llc_seq_socket_show(struct seq_file *seq, void *v) static int llc_seq_socket_show(struct seq_file *seq, void *v)
......
...@@ -17,13 +17,14 @@ ...@@ -17,13 +17,14 @@
* *
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*/ */
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <net/llc_if.h> #include <net/llc.h>
#include <net/llc_sap.h>
#include <net/llc_main.h>
#include <net/llc_s_ev.h>
#include <net/llc_pdu.h> #include <net/llc_pdu.h>
#include <net/llc_mac.h> #include <net/llc_s_ac.h>
#include <net/llc_s_ev.h>
#include <net/llc_sap.h>
#include "llc_output.h"
/** /**
* llc_sap_action_unit_data_ind - forward UI PDU to network layer * llc_sap_action_unit_data_ind - forward UI PDU to network layer
...@@ -56,7 +57,7 @@ int llc_sap_action_send_ui(struct llc_sap *sap, struct sk_buff *skb) ...@@ -56,7 +57,7 @@ int llc_sap_action_send_ui(struct llc_sap *sap, struct sk_buff *skb)
llc_pdu_header_init(skb, LLC_PDU_TYPE_U, ev->saddr.lsap, llc_pdu_header_init(skb, LLC_PDU_TYPE_U, ev->saddr.lsap,
ev->daddr.lsap, LLC_PDU_CMD); ev->daddr.lsap, LLC_PDU_CMD);
llc_pdu_init_as_ui_cmd(skb); llc_pdu_init_as_ui_cmd(skb);
rc = lan_hdrs_init(skb, ev->saddr.mac, ev->daddr.mac); rc = llc_mac_hdr_init(skb, ev->saddr.mac, ev->daddr.mac);
if (!rc) if (!rc)
rc = dev_queue_xmit(skb); rc = dev_queue_xmit(skb);
return rc; return rc;
...@@ -79,7 +80,7 @@ int llc_sap_action_send_xid_c(struct llc_sap *sap, struct sk_buff *skb) ...@@ -79,7 +80,7 @@ int llc_sap_action_send_xid_c(struct llc_sap *sap, struct sk_buff *skb)
llc_pdu_header_init(skb, LLC_PDU_TYPE_U, ev->saddr.lsap, llc_pdu_header_init(skb, LLC_PDU_TYPE_U, ev->saddr.lsap,
ev->daddr.lsap, LLC_PDU_CMD); ev->daddr.lsap, LLC_PDU_CMD);
llc_pdu_init_as_xid_cmd(skb, LLC_XID_NULL_CLASS_2, 0); llc_pdu_init_as_xid_cmd(skb, LLC_XID_NULL_CLASS_2, 0);
rc = lan_hdrs_init(skb, ev->saddr.mac, ev->daddr.mac); rc = llc_mac_hdr_init(skb, ev->saddr.mac, ev->daddr.mac);
if (!rc) if (!rc)
rc = dev_queue_xmit(skb); rc = dev_queue_xmit(skb);
return rc; return rc;
...@@ -109,7 +110,7 @@ int llc_sap_action_send_xid_r(struct llc_sap *sap, struct sk_buff *skb) ...@@ -109,7 +110,7 @@ int llc_sap_action_send_xid_r(struct llc_sap *sap, struct sk_buff *skb)
llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, dsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, dsap,
LLC_PDU_RSP); LLC_PDU_RSP);
llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 0); llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 0);
rc = lan_hdrs_init(nskb, mac_sa, mac_da); rc = llc_mac_hdr_init(nskb, mac_sa, mac_da);
if (!rc) if (!rc)
rc = dev_queue_xmit(nskb); rc = dev_queue_xmit(nskb);
out: out:
...@@ -133,7 +134,7 @@ int llc_sap_action_send_test_c(struct llc_sap *sap, struct sk_buff *skb) ...@@ -133,7 +134,7 @@ int llc_sap_action_send_test_c(struct llc_sap *sap, struct sk_buff *skb)
llc_pdu_header_init(skb, LLC_PDU_TYPE_U, ev->saddr.lsap, llc_pdu_header_init(skb, LLC_PDU_TYPE_U, ev->saddr.lsap,
ev->daddr.lsap, LLC_PDU_CMD); ev->daddr.lsap, LLC_PDU_CMD);
llc_pdu_init_as_test_cmd(skb); llc_pdu_init_as_test_cmd(skb);
rc = lan_hdrs_init(skb, ev->saddr.mac, ev->daddr.mac); rc = llc_mac_hdr_init(skb, ev->saddr.mac, ev->daddr.mac);
if (!rc) if (!rc)
rc = dev_queue_xmit(skb); rc = dev_queue_xmit(skb);
return rc; return rc;
...@@ -155,7 +156,7 @@ int llc_sap_action_send_test_r(struct llc_sap *sap, struct sk_buff *skb) ...@@ -155,7 +156,7 @@ int llc_sap_action_send_test_r(struct llc_sap *sap, struct sk_buff *skb)
llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, dsap, llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, dsap,
LLC_PDU_RSP); LLC_PDU_RSP);
llc_pdu_init_as_test_rsp(nskb, skb); llc_pdu_init_as_test_rsp(nskb, skb);
rc = lan_hdrs_init(nskb, mac_sa, mac_da); rc = llc_mac_hdr_init(nskb, mac_sa, mac_da);
if (!rc) if (!rc)
rc = dev_queue_xmit(nskb); rc = dev_queue_xmit(nskb);
out: out:
......
...@@ -11,17 +11,38 @@ ...@@ -11,17 +11,38 @@
* *
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*/ */
#include <linux/skbuff.h>
#include <net/llc.h>
#include <net/llc_if.h>
#include <net/llc_conn.h> #include <net/llc_conn.h>
#include <net/llc_pdu.h>
#include <net/llc_sap.h> #include <net/llc_sap.h>
#include <net/llc_s_ev.h>
#include <net/llc_s_ac.h> #include <net/llc_s_ac.h>
#include <net/llc_s_ev.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 <linux/tcp.h>
#include <net/llc_main.h> #include <linux/llc.h>
#include <net/llc_pdu.h>
#include <linux/if_tr.h> /**
* llc_alloc_frame - allocates sk_buff for frame
*
* Allocates an sk_buff for frame and initializes sk_buff fields.
* Returns allocated skb or %NULL when out of memory.
*/
struct sk_buff *llc_alloc_frame(void)
{
struct sk_buff *skb = alloc_skb(128, GFP_ATOMIC);
if (skb) {
skb_reserve(skb, 50);
skb->nh.raw = skb->h.raw = skb->data;
skb->protocol = htons(ETH_P_802_2);
skb->dev = dev_base->next;
skb->mac.raw = skb->head;
}
return skb;
}
void llc_save_primitive(struct sk_buff* skb, u8 prim) void llc_save_primitive(struct sk_buff* skb, u8 prim)
{ {
...@@ -180,36 +201,6 @@ void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb) ...@@ -180,36 +201,6 @@ void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb)
kfree_skb(skb); kfree_skb(skb);
} }
/**
* llc_build_and_send_ui_pkt - unitdata request interface for upper layers
* @sap: sap to use
* @skb: packet to send
* @dmac: destination mac address
* @dsap: destination sap
*
* Upper layers calls this function when upper layer wants to send data
* using connection-less mode communication (UI pdu).
*
* Accept data frame from network layer to be sent using connection-
* less mode communication; timeout/retries handled by network layer;
* package primitive as an event and send to SAP event handler
*/
void llc_build_and_send_ui_pkt(struct llc_sap *sap, struct sk_buff *skb,
u8 *dmac, u8 dsap)
{
struct llc_sap_state_ev *ev = llc_sap_ev(skb);
ev->saddr.lsap = sap->laddr.lsap;
ev->daddr.lsap = dsap;
memcpy(ev->saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
memcpy(ev->daddr.mac, dmac, IFHWADDRLEN);
ev->type = LLC_SAP_EV_TYPE_PRIM;
ev->prim = LLC_DATAUNIT_PRIM;
ev->prim_type = LLC_PRIM_TYPE_REQ;
llc_sap_state_process(sap, skb);
}
/** /**
* llc_build_and_send_test_pkt - TEST interface for upper layers. * llc_build_and_send_test_pkt - TEST interface for upper layers.
* @sap: sap to use * @sap: sap to use
...@@ -325,79 +316,6 @@ void llc_sap_handler(struct llc_sap *sap, struct sk_buff *skb) ...@@ -325,79 +316,6 @@ void llc_sap_handler(struct llc_sap *sap, struct sk_buff *skb)
kfree_skb(skb); kfree_skb(skb);
} }
/**
* llc_sap_alloc - allocates and initializes sap.
*
* Allocates and initializes sap.
*/
struct llc_sap *llc_sap_alloc(void)
{
struct llc_sap *sap = kmalloc(sizeof(*sap), GFP_ATOMIC);
if (sap) {
memset(sap, 0, sizeof(*sap));
sap->state = LLC_SAP_STATE_ACTIVE;
memcpy(sap->laddr.mac, llc_main_station.mac_sa, ETH_ALEN);
rwlock_init(&sap->sk_list.lock);
}
return sap;
}
/**
* llc_sap_open - open interface to the upper layers.
* @lsap: SAP number.
* @func: rcv func for datalink protos
*
* Interface function to upper layer. Each one who wants to get a SAP
* (for example NetBEUI) should call this function. Returns the opened
* SAP for success, NULL for failure.
*/
struct llc_sap *llc_sap_open(u8 lsap, int (*func)(struct sk_buff *skb,
struct net_device *dev,
struct packet_type *pt))
{
/* verify this SAP is not already open; if so, return error */
struct llc_sap *sap;
sap = llc_sap_find(lsap);
if (sap) { /* SAP already exists */
sap = NULL;
goto out;
}
/* sap requested does not yet exist */
sap = llc_sap_alloc();
if (!sap)
goto out;
/* allocated a SAP; initialize it and clear out its memory pool */
sap->laddr.lsap = lsap;
sap->rcv_func = func;
sap->station = &llc_main_station;
/* initialized SAP; add it to list of SAPs this station manages */
llc_sap_save(sap);
out:
return sap;
}
/**
* llc_sap_close - close interface for upper layers.
* @sap: SAP to be closed.
*
* Close interface function to upper layer. Each one who wants to
* close an open SAP (for example NetBEUI) should call this function.
* Removes this sap from the list of saps in the station and then
* frees the memory for this sap.
*/
void llc_sap_close(struct llc_sap *sap)
{
WARN_ON(!hlist_empty(&sap->sk_list.list));
write_lock_bh(&sap->station->sap_list.lock);
list_del(&sap->node);
write_unlock_bh(&sap->station->sap_list.lock);
kfree(sap);
}
EXPORT_SYMBOL(llc_sap_open);
EXPORT_SYMBOL(llc_sap_close);
EXPORT_SYMBOL(llc_save_primitive); EXPORT_SYMBOL(llc_save_primitive);
EXPORT_SYMBOL(llc_build_and_send_test_pkt); EXPORT_SYMBOL(llc_build_and_send_test_pkt);
EXPORT_SYMBOL(llc_build_and_send_ui_pkt); EXPORT_SYMBOL(llc_build_and_send_ui_pkt);
......
/* /*
* llc_stat.c - Implementation of LLC station component state machine * llc_station.c - station component of LLC
* transitions *
* Copyright (c) 1997 by Procom Technology, Inc. * Copyright (c) 1997 by Procom Technology, Inc.
* 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> * 2001-2003 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
* *
...@@ -11,12 +11,315 @@ ...@@ -11,12 +11,315 @@
* *
* See the GNU General Public License for more details. * See the GNU General Public License for more details.
*/ */
#include <linux/types.h> #include <linux/config.h>
#include <net/llc_if.h> #include <linux/init.h>
#include <linux/module.h>
#include <net/llc.h>
#include <net/llc_sap.h> #include <net/llc_sap.h>
#include <net/llc_evnt.h> #include <net/llc_conn.h>
#include <net/llc_actn.h> #include <net/llc_c_ac.h>
#include <net/llc_stat.h> #include <net/llc_s_ac.h>
#include <net/llc_c_ev.h>
#include <net/llc_c_st.h>
#include <net/llc_s_ev.h>
#include <net/llc_s_st.h>
#include <net/llc_pdu.h>
/**
* struct llc_station - LLC station component
*
* SAP and connection resource manager, one per adapter.
*
* @state - state of station
* @xid_r_count - XID response PDU counter
* @mac_sa - MAC source address
* @sap_list - list of related SAPs
* @ev_q - events entering state mach.
* @mac_pdu_q - PDUs ready to send to MAC
*/
struct llc_station {
u8 state;
u8 xid_r_count;
struct timer_list ack_timer;
u8 retry_count;
u8 maximum_retry;
struct {
struct sk_buff_head list;
spinlock_t lock;
} ev_q;
struct sk_buff_head mac_pdu_q;
};
/* Types of events (possible values in 'ev->type') */
#define LLC_STATION_EV_TYPE_SIMPLE 1
#define LLC_STATION_EV_TYPE_CONDITION 2
#define LLC_STATION_EV_TYPE_PRIM 3
#define LLC_STATION_EV_TYPE_PDU 4 /* command/response PDU */
#define LLC_STATION_EV_TYPE_ACK_TMR 5
#define LLC_STATION_EV_TYPE_RPT_STATUS 6
/* Events */
#define LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK 1
#define LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK 2
#define LLC_STATION_EV_ACK_TMR_EXP_LT_RETRY_CNT_MAX_RETRY 3
#define LLC_STATION_EV_ACK_TMR_EXP_EQ_RETRY_CNT_MAX_RETRY 4
#define LLC_STATION_EV_RX_NULL_DSAP_XID_C 5
#define LLC_STATION_EV_RX_NULL_DSAP_0_XID_R_XID_R_CNT_EQ 6
#define LLC_STATION_EV_RX_NULL_DSAP_1_XID_R_XID_R_CNT_EQ 7
#define LLC_STATION_EV_RX_NULL_DSAP_TEST_C 8
#define LLC_STATION_EV_DISABLE_REQ 9
struct llc_station_state_ev {
u8 type;
u8 prim;
u8 prim_type;
u8 reason;
struct list_head node; /* node in station->ev_q.list */
};
static __inline__ struct llc_station_state_ev *
llc_station_ev(struct sk_buff *skb)
{
return (struct llc_station_state_ev *)skb->cb;
}
typedef int (*llc_station_ev_t)(struct sk_buff *skb);
#define LLC_STATION_STATE_DOWN 1 /* initial state */
#define LLC_STATION_STATE_DUP_ADDR_CHK 2
#define LLC_STATION_STATE_UP 3
#define LLC_NBR_STATION_STATES 3 /* size of state table */
typedef int (*llc_station_action_t)(struct sk_buff *skb);
/* Station component state table structure */
struct llc_station_state_trans {
llc_station_ev_t ev;
u8 next_state;
llc_station_action_t *ev_actions;
};
struct llc_station_state {
u8 curr_state;
struct llc_station_state_trans **transitions;
};
static struct llc_station llc_main_station;
static int llc_stat_ev_enable_with_dup_addr_check(struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
return ev->type == LLC_STATION_EV_TYPE_SIMPLE &&
ev->prim_type ==
LLC_STATION_EV_ENABLE_WITH_DUP_ADDR_CHECK ? 0 : 1;
}
static int llc_stat_ev_enable_without_dup_addr_check(struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
return ev->type == LLC_STATION_EV_TYPE_SIMPLE &&
ev->prim_type ==
LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK ? 0 : 1;
}
static int llc_stat_ev_ack_tmr_exp_lt_retry_cnt_max_retry(struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
return ev->type == LLC_STATION_EV_TYPE_ACK_TMR &&
llc_main_station.retry_count <
llc_main_station.maximum_retry ? 0 : 1;
}
static int llc_stat_ev_ack_tmr_exp_eq_retry_cnt_max_retry(struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
return ev->type == LLC_STATION_EV_TYPE_ACK_TMR &&
llc_main_station.retry_count ==
llc_main_station.maximum_retry ? 0 : 1;
}
static int llc_stat_ev_rx_null_dsap_xid_c(struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
return ev->type == LLC_STATION_EV_TYPE_PDU &&
LLC_PDU_IS_CMD(pdu) && /* command PDU */
LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */
LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_XID &&
!pdu->dsap ? 0 : 1; /* NULL DSAP value */
}
static int llc_stat_ev_rx_null_dsap_0_xid_r_xid_r_cnt_eq(struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
return ev->type == LLC_STATION_EV_TYPE_PDU &&
LLC_PDU_IS_RSP(pdu) && /* response PDU */
LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */
LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID &&
!pdu->dsap && /* NULL DSAP value */
!llc_main_station.xid_r_count ? 0 : 1;
}
static int llc_stat_ev_rx_null_dsap_1_xid_r_xid_r_cnt_eq(struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
return ev->type == LLC_STATION_EV_TYPE_PDU &&
LLC_PDU_IS_RSP(pdu) && /* response PDU */
LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */
LLC_U_PDU_RSP(pdu) == LLC_1_PDU_CMD_XID &&
!pdu->dsap && /* NULL DSAP value */
llc_main_station.xid_r_count == 1 ? 0 : 1;
}
static int llc_stat_ev_rx_null_dsap_test_c(struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
return ev->type == LLC_STATION_EV_TYPE_PDU &&
LLC_PDU_IS_CMD(pdu) && /* command PDU */
LLC_PDU_TYPE_IS_U(pdu) && /* U type PDU */
LLC_U_PDU_CMD(pdu) == LLC_1_PDU_CMD_TEST &&
!pdu->dsap ? 0 : 1; /* NULL DSAP */
}
static int llc_stat_ev_disable_req(struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
return ev->type == LLC_STATION_EV_TYPE_PRIM &&
ev->prim == LLC_DISABLE_PRIM &&
ev->prim_type == LLC_PRIM_TYPE_REQ ? 0 : 1;
}
/**
* llc_station_send_pdu - queues PDU to send
* @skb: Address of the PDU
*
* Queues a PDU to send to the MAC layer.
*/
static void llc_station_send_pdu(struct sk_buff *skb)
{
skb_queue_tail(&llc_main_station.mac_pdu_q, skb);
while ((skb = skb_dequeue(&llc_main_station.mac_pdu_q)) != NULL)
if (dev_queue_xmit(skb))
break;
}
static int llc_station_ac_start_ack_timer(struct sk_buff *skb)
{
mod_timer(&llc_main_station.ack_timer, jiffies + LLC_ACK_TIME * HZ);
return 0;
}
static int llc_station_ac_set_retry_cnt_0(struct sk_buff *skb)
{
llc_main_station.retry_count = 0;
return 0;
}
static int llc_station_ac_inc_retry_cnt_by_1(struct sk_buff *skb)
{
llc_main_station.retry_count++;
return 0;
}
static int llc_station_ac_set_xid_r_cnt_0(struct sk_buff *skb)
{
llc_main_station.xid_r_count = 0;
return 0;
}
static int llc_station_ac_inc_xid_r_cnt_by_1(struct sk_buff *skb)
{
llc_main_station.xid_r_count++;
return 0;
}
static int llc_station_ac_send_null_dsap_xid_c(struct sk_buff *skb)
{
int rc = 1;
struct sk_buff *nskb = llc_alloc_frame();
if (!nskb)
goto out;
llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, 0, LLC_PDU_CMD);
llc_pdu_init_as_xid_cmd(nskb, LLC_XID_NULL_CLASS_2, 127);
rc = llc_mac_hdr_init(nskb, llc_station_mac_sa, llc_station_mac_sa);
if (rc)
goto free;
llc_station_send_pdu(nskb);
out:
return rc;
free:
kfree_skb(skb);
goto out;
}
static int llc_station_ac_send_xid_r(struct sk_buff *skb)
{
u8 mac_da[ETH_ALEN], dsap;
int rc = 1;
struct sk_buff* nskb = llc_alloc_frame();
if (!nskb)
goto out;
rc = 0;
nskb->dev = skb->dev;
llc_pdu_decode_sa(skb, mac_da);
llc_pdu_decode_ssap(skb, &dsap);
llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 127);
rc = llc_mac_hdr_init(nskb, llc_station_mac_sa, mac_da);
if (rc)
goto free;
llc_station_send_pdu(nskb);
out:
return rc;
free:
kfree_skb(skb);
goto out;
}
static int llc_station_ac_send_test_r(struct sk_buff *skb)
{
u8 mac_da[ETH_ALEN], dsap;
int rc = 1;
struct sk_buff *nskb = llc_alloc_frame();
if (!nskb)
goto out;
rc = 0;
nskb->dev = skb->dev;
llc_pdu_decode_sa(skb, mac_da);
llc_pdu_decode_ssap(skb, &dsap);
llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, 0, dsap, LLC_PDU_RSP);
llc_pdu_init_as_test_rsp(nskb, skb);
rc = llc_mac_hdr_init(nskb, llc_station_mac_sa, mac_da);
if (rc)
goto free;
llc_station_send_pdu(nskb);
out:
return rc;
free:
kfree_skb(skb);
goto out;
}
static int llc_station_ac_report_status(struct sk_buff *skb)
{
return 0;
}
/* COMMON STATION STATE transitions */ /* COMMON STATION STATE transitions */
...@@ -202,7 +505,8 @@ static struct llc_station_state_trans *llc_stat_dupaddr_state_trans[] = { ...@@ -202,7 +505,8 @@ static struct llc_station_state_trans *llc_stat_dupaddr_state_trans[] = {
[6] = &llc_stat_state_trans_end, [6] = &llc_stat_state_trans_end,
}; };
struct llc_station_state llc_station_state_table[LLC_NBR_STATION_STATES] = { static struct llc_station_state
llc_station_state_table[LLC_NBR_STATION_STATES] = {
[LLC_STATION_STATE_DOWN - 1] = { [LLC_STATION_STATE_DOWN - 1] = {
.curr_state = LLC_STATION_STATE_DOWN, .curr_state = LLC_STATION_STATE_DOWN,
.transitions = llc_stat_dwn_state_trans, .transitions = llc_stat_dwn_state_trans,
...@@ -216,3 +520,194 @@ struct llc_station_state llc_station_state_table[LLC_NBR_STATION_STATES] = { ...@@ -216,3 +520,194 @@ struct llc_station_state llc_station_state_table[LLC_NBR_STATION_STATES] = {
.transitions = llc_stat_up_state_trans, .transitions = llc_stat_up_state_trans,
}, },
}; };
/**
* llc_exec_station_trans_actions - executes actions for transition
* @trans: Address of the transition
* @skb: Address of the event that caused the transition
*
* Executes actions of a transition of the station state machine. Returns
* 0 if all actions complete successfully, nonzero otherwise.
*/
static u16 llc_exec_station_trans_actions(struct llc_station_state_trans *trans,
struct sk_buff *skb)
{
u16 rc = 0;
llc_station_action_t *next_action = trans->ev_actions;
for (; next_action && *next_action; next_action++)
if ((*next_action)(skb))
rc = 1;
return rc;
}
/**
* llc_find_station_trans - finds transition for this event
* @skb: Address of the event
*
* Search thru events of the current state of the station until list
* exhausted or it's obvious that the event is not valid for the current
* state. Returns the address of the transition if cound, %NULL otherwise.
*/
static struct llc_station_state_trans *
llc_find_station_trans(struct sk_buff *skb)
{
int i = 0;
struct llc_station_state_trans *rc = NULL;
struct llc_station_state_trans **next_trans;
struct llc_station_state *curr_state =
&llc_station_state_table[llc_main_station.state - 1];
for (next_trans = curr_state->transitions; next_trans[i]->ev; i++)
if (!next_trans[i]->ev(skb)) {
rc = next_trans[i];
break;
}
return rc;
}
/**
* llc_station_free_ev - frees an event
* @skb: Address of the event
*
* Frees an event.
*/
static void llc_station_free_ev(struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
if (ev->type == LLC_STATION_EV_TYPE_PDU)
kfree_skb(skb);
}
/**
* llc_station_next_state - processes event and goes to the next state
* @skb: Address of the event
*
* Processes an event, executes any transitions related to that event and
* updates the state of the station.
*/
static u16 llc_station_next_state(struct sk_buff *skb)
{
u16 rc = 1;
struct llc_station_state_trans *trans;
if (llc_main_station.state > LLC_NBR_STATION_STATES)
goto out;
trans = llc_find_station_trans(skb);
if (trans) {
/* got the state to which we next transition; perform the
* actions associated with this transition before actually
* transitioning to the next state
*/
rc = llc_exec_station_trans_actions(trans, skb);
if (!rc)
/* transition station to next state if all actions
* execute successfully; done; wait for next event
*/
llc_main_station.state = trans->next_state;
} else
/* event not recognized in current state; re-queue it for
* processing again at a later time; return failure
*/
rc = 0;
out:
llc_station_free_ev(skb);
return rc;
}
/**
* llc_station_service_events - service events in the queue
*
* Get an event from the station event queue (if any); attempt to service
* the event; if event serviced, get the next event (if any) on the event
* queue; if event not service, re-queue the event on the event queue and
* attempt to service the next event; when serviced all events in queue,
* finished; if don't transition to different state, just service all
* events once; if transition to new state, service all events again.
* Caller must hold llc_main_station.ev_q.lock.
*/
static void llc_station_service_events(void)
{
struct sk_buff *skb;
while ((skb = skb_dequeue(&llc_main_station.ev_q.list)) != NULL)
llc_station_next_state(skb);
}
/**
* llc_station_state_process: queue event and try to process queue.
* @skb: Address of the event
*
* Queues an event (on the station event queue) for handling by the
* station state machine and attempts to process any queued-up events.
*/
void llc_station_state_process(struct sk_buff *skb)
{
spin_lock_bh(&llc_main_station.ev_q.lock);
skb_queue_tail(&llc_main_station.ev_q.list, skb);
llc_station_service_events();
spin_unlock_bh(&llc_main_station.ev_q.lock);
}
static void llc_station_ack_tmr_cb(unsigned long timeout_data)
{
struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
if (skb) {
struct llc_station_state_ev *ev = llc_station_ev(skb);
ev->type = LLC_STATION_EV_TYPE_ACK_TMR;
llc_station_state_process(skb);
}
}
/*
* llc_station_rcv - send received pdu to the station state machine
* @skb: received frame.
*
* Sends data unit to station state machine.
*/
static void llc_station_rcv(struct sk_buff *skb)
{
struct llc_station_state_ev *ev = llc_station_ev(skb);
ev->type = LLC_STATION_EV_TYPE_PDU;
ev->reason = 0;
llc_station_state_process(skb);
}
int __init llc_station_init(void)
{
u16 rc = -ENOBUFS;
struct sk_buff *skb;
struct llc_station_state_ev *ev;
skb_queue_head_init(&llc_main_station.mac_pdu_q);
skb_queue_head_init(&llc_main_station.ev_q.list);
spin_lock_init(&llc_main_station.ev_q.lock);
init_timer(&llc_main_station.ack_timer);
llc_main_station.ack_timer.data = (unsigned long)&llc_main_station;
llc_main_station.ack_timer.function = llc_station_ack_tmr_cb;
skb = alloc_skb(0, GFP_ATOMIC);
if (!skb)
goto out;
rc = 0;
llc_set_station_handler(llc_station_rcv);
ev = llc_station_ev(skb);
memset(ev, 0, sizeof(*ev));
llc_main_station.ack_timer.expires = jiffies + 3 * HZ;
llc_main_station.maximum_retry = 1;
llc_main_station.state = LLC_STATION_STATE_DOWN;
ev->type = LLC_STATION_EV_TYPE_SIMPLE;
ev->prim_type = LLC_STATION_EV_ENABLE_WITHOUT_DUP_ADDR_CHECK;
rc = llc_station_next_state(skb);
out:
return rc;
}
void __exit llc_station_exit(void)
{
llc_set_station_handler(NULL);
}
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