Commit 06a11c36 authored by David S. Miller's avatar David S. Miller

Merge nuts.ninka.net:/home/davem/src/BK/llc-2.5

into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents c91bb36d ed54ae2e
...@@ -78,17 +78,6 @@ enum llc_sockopts { ...@@ -78,17 +78,6 @@ enum llc_sockopts {
#define LLC_SAP_DYN_STOP 0xDE #define LLC_SAP_DYN_STOP 0xDE
#define LLC_SAP_DYN_TRIES 4 #define LLC_SAP_DYN_TRIES 4
struct sock;
struct llc_ui_opt {
u16 link; /* network layer link number */
struct llc_sap *sap; /* pointer to parent SAP */
struct sock *core_sk;
struct net_device *dev; /* device to send to remote */
struct sockaddr_llc addr; /* address sock is bound to */
};
#define llc_ui_sk(__sk) ((struct llc_ui_opt *)(__sk)->protinfo)
#define llc_ui_skb_cb(__skb) ((struct sockaddr_llc *)&((__skb)->cb[0])) #define llc_ui_skb_cb(__skb) ((struct sockaddr_llc *)&((__skb)->cb[0]))
#ifdef CONFIG_LLC_UI #ifdef CONFIG_LLC_UI
......
...@@ -33,15 +33,15 @@ ...@@ -33,15 +33,15 @@
/* Connection state table structure */ /* Connection state table structure */
struct llc_conn_state_trans { struct llc_conn_state_trans {
llc_conn_ev_t ev; llc_conn_ev_t ev;
u8 next_state; u8 next_state;
llc_conn_ev_qfyr_t *ev_qualifiers; llc_conn_ev_qfyr_t *ev_qualifiers;
llc_conn_action_t *ev_actions; llc_conn_action_t *ev_actions;
}; };
struct llc_conn_state { struct llc_conn_state {
u8 current_state; u8 current_state;
struct llc_conn_state_trans **transitions; struct llc_conn_state_trans **transitions;
}; };
extern struct llc_conn_state llc_conn_state_table[]; extern struct llc_conn_state llc_conn_state_table[];
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#define LLC_CONN_H #define LLC_CONN_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, 2002 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.
...@@ -13,8 +13,7 @@ ...@@ -13,8 +13,7 @@
*/ */
#include <linux/timer.h> #include <linux/timer.h>
#include <net/llc_if.h> #include <net/llc_if.h>
#include <linux/llc.h>
#undef DEBUG_LLC_CONN_ALLOC
struct llc_timer { struct llc_timer {
struct timer_list timer; struct timer_list timer;
...@@ -25,7 +24,7 @@ struct llc_timer { ...@@ -25,7 +24,7 @@ struct llc_timer {
struct llc_opt { struct llc_opt {
struct list_head node; /* entry in sap->sk_list.list */ struct list_head node; /* entry in sap->sk_list.list */
struct sock *sk; /* sock that has this llc_opt */ struct sock *sk; /* sock that has this llc_opt */
void *handler; /* for upper layers usage */ struct sockaddr_llc addr; /* address sock is bound to */
u8 state; /* state of connection */ u8 state; /* state of connection */
struct llc_sap *sap; /* pointer to parent SAP */ struct llc_sap *sap; /* pointer to parent SAP */
struct llc_addr laddr; /* lsap/mac pair */ struct llc_addr laddr; /* lsap/mac pair */
...@@ -80,63 +79,14 @@ struct llc_opt { ...@@ -80,63 +79,14 @@ struct llc_opt {
struct llc_conn_state_ev; struct llc_conn_state_ev;
extern struct sock *__llc_sock_alloc(void); extern struct sock *llc_sk_alloc(int family, int priority);
extern void __llc_sock_free(struct sock *sk, u8 free); extern void llc_sk_free(struct sock *sk);
#ifdef DEBUG_LLC_CONN_ALLOC
#define dump_stack() printk(KERN_INFO "call trace: %p, %p, %p\n", \
__builtin_return_address(0), \
__builtin_return_address(1), \
__builtin_return_address(2));
#define llc_sock_alloc() ({ \
struct sock *__sk = __llc_sock_alloc(); \
if (__sk) { \
llc_sk(__sk)->f_alloc = __FUNCTION__; \
llc_sk(__sk)->l_alloc = __LINE__; \
} \
__sk;})
#define __llc_sock_assert(__sk) \
if (llc_sk(__sk)->f_free) { \
printk(KERN_ERR \
"%p conn (alloc'd @ %s(%d)) " \
"already freed @ %s(%d) " \
"being used again @ %s(%d)\n", \
llc_sk(__sk), \
llc_sk(__sk)->f_alloc, llc_sk(__sk)->l_alloc, \
llc_sk(__sk)->f_free, llc_sk(__sk)->l_free, \
__FUNCTION__, __LINE__); \
dump_stack();
#define llc_sock_free(__sk) \
{ \
__llc_sock_assert(__sk) \
} else { \
__llc_sock_free(__sk, 0); \
llc_sk(__sk)->f_free = __FUNCTION__; \
llc_sk(__sk)->l_free = __LINE__; \
} \
}
#define llc_sock_assert(__sk) \
{ \
__llc_sock_assert(__sk); \
return; } \
}
#define llc_sock_assert_ret(__sk, __ret) \
{ \
__llc_sock_assert(__sk); \
return __ret; } \
}
#else /* DEBUG_LLC_CONN_ALLOC */
#define llc_sock_alloc() __llc_sock_alloc()
#define llc_sock_free(__sk) __llc_sock_free(__sk, 1)
#define llc_sock_assert(__sk)
#define llc_sock_assert_ret(__sk)
#endif /* DEBUG_LLC_CONN_ALLOC */
extern void llc_sock_reset(struct sock *sk); extern void llc_sk_reset(struct sock *sk);
extern int llc_sock_init(struct sock *sk); extern int llc_sk_init(struct sock *sk);
/* Access to a connection */ /* Access to a connection */
extern int llc_conn_send_ev(struct sock *sk, struct sk_buff *skb); extern int llc_conn_state_process(struct sock *sk, struct sk_buff *skb);
extern void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb); extern void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb);
extern void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb); extern void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb);
extern void llc_conn_free_ev(struct sk_buff *skb); extern void llc_conn_free_ev(struct sk_buff *skb);
...@@ -146,8 +96,11 @@ extern void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr, ...@@ -146,8 +96,11 @@ extern void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr,
u8 first_f_bit); u8 first_f_bit);
extern int llc_conn_remove_acked_pdus(struct sock *conn, u8 nr, extern int llc_conn_remove_acked_pdus(struct sock *conn, u8 nr,
u16 *how_many_unacked); u16 *how_many_unacked);
extern struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr, extern struct sock *llc_lookup_established(struct llc_sap *sap,
struct llc_addr *laddr); struct llc_addr *daddr,
struct llc_addr *laddr);
extern struct sock *llc_lookup_listener(struct llc_sap *sap,
struct llc_addr *laddr);
extern u8 llc_data_accept_state(u8 state); extern u8 llc_data_accept_state(u8 state);
extern void llc_build_offset_table(void); extern void llc_build_offset_table(void);
#endif /* LLC_CONN_H */ #endif /* LLC_CONN_H */
...@@ -14,13 +14,15 @@ ...@@ -14,13 +14,15 @@
/* Defines LLC interface to network layer */ /* Defines LLC interface to network layer */
/* Available primitives */ /* Available primitives */
#include <linux/if.h> #include <linux/if.h>
#include <linux/if_arp.h>
#include <linux/llc.h>
#define LLC_DATAUNIT_PRIM 0 #define LLC_DATAUNIT_PRIM 0
#define LLC_CONN_PRIM 1 #define LLC_CONN_PRIM 1
#define LLC_DATA_PRIM 2 #define LLC_DATA_PRIM 2
#define LLC_DISC_PRIM 3 #define LLC_DISC_PRIM 3
#define LLC_RESET_PRIM 4 #define LLC_RESET_PRIM 4
#define LLC_FLOWCONTROL_PRIM 5 #define LLC_FLOWCONTROL_PRIM 5 /* Not supported at this time */
#define LLC_DISABLE_PRIM 6 #define LLC_DISABLE_PRIM 6
#define LLC_XID_PRIM 7 #define LLC_XID_PRIM 7
#define LLC_TEST_PRIM 8 #define LLC_TEST_PRIM 8
...@@ -65,46 +67,12 @@ struct llc_addr { ...@@ -65,46 +67,12 @@ struct llc_addr {
u8 mac[IFHWADDRLEN]; u8 mac[IFHWADDRLEN];
}; };
/* Primitive-specific data */
struct llc_prim_conn {
struct llc_addr saddr; /* used by request only */
struct llc_addr daddr; /* used by request only */
u8 status; /* reason for failure */
u8 pri; /* service_class */
struct net_device *dev;
struct sock *sk; /* returned from REQUEST */
void *handler; /* upper layer use,
stored in llc_opt->handler */
u16 link;
struct sk_buff *skb; /* received SABME */
};
struct llc_prim_disc {
struct sock *sk;
u16 link;
u8 reason; /* not used by request */
};
struct llc_prim_reset { struct llc_prim_reset {
struct sock *sk; struct sock *sk;
u16 link; u16 link;
u8 reason; /* used only by indicate */ u8 reason; /* used only by indicate */
}; };
struct llc_prim_flow_ctrl {
struct sock *sk;
u16 link;
u32 amount;
};
struct llc_prim_data {
struct sock *sk;
u16 link;
u8 pri;
struct sk_buff *skb; /* pointer to frame */
u8 status; /* reason */
};
/* Sending data in conection-less mode */ /* Sending data in conection-less mode */
struct llc_prim_unit_data { struct llc_prim_unit_data {
struct llc_addr saddr; struct llc_addr saddr;
...@@ -129,11 +97,7 @@ struct llc_prim_test { ...@@ -129,11 +97,7 @@ struct llc_prim_test {
}; };
union llc_u_prim_data { union llc_u_prim_data {
struct llc_prim_conn conn;
struct llc_prim_disc disc;
struct llc_prim_reset res; struct llc_prim_reset res;
struct llc_prim_flow_ctrl fc;
struct llc_prim_data data; /* data */
struct llc_prim_unit_data udata; /* unit data */ struct llc_prim_unit_data udata; /* unit data */
struct llc_prim_xid xid; struct llc_prim_xid xid;
struct llc_prim_test test; struct llc_prim_test test;
...@@ -152,4 +116,30 @@ typedef int (*llc_prim_call_t)(struct llc_prim_if_block *prim_if); ...@@ -152,4 +116,30 @@ typedef int (*llc_prim_call_t)(struct llc_prim_if_block *prim_if);
extern struct llc_sap *llc_sap_open(llc_prim_call_t network_indicate, extern struct llc_sap *llc_sap_open(llc_prim_call_t network_indicate,
llc_prim_call_t network_confirm, u8 lsap); llc_prim_call_t network_confirm, u8 lsap);
extern void llc_sap_close(struct llc_sap *sap); extern void llc_sap_close(struct llc_sap *sap);
extern int llc_establish_connection(struct sock *sk, u8 *lmac,
u8 *dmac, u8 dsap);
extern int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb);
extern void llc_build_and_send_ui_pkt(struct llc_sap *sap,
struct sk_buff *skb,
struct sockaddr_llc *addr);
extern void llc_build_and_send_xid_pkt(struct llc_sap *sap,
struct sk_buff *skb,
struct sockaddr_llc *addr);
extern void llc_build_and_send_test_pkt(struct llc_sap *sap,
struct sk_buff *skb,
struct sockaddr_llc *addr);
extern int llc_send_disc(struct sock *sk);
/**
* llc_proto_type - return eth protocol for ARP header type
* @arphrd: ARP header type.
*
* Given an ARP header type return the corresponding ethernet protocol.
*/
static __inline__ u16 llc_proto_type(u16 arphrd)
{
return arphrd == ARPHRD_IEEE802_TR ?
htons(ETH_P_TR_802_2) : htons(ETH_P_802_2);
}
#endif /* LLC_IF_H */ #endif /* LLC_IF_H */
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#define LLC_MAC_H #define LLC_MAC_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, 2002 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.
...@@ -13,13 +13,12 @@ ...@@ -13,13 +13,12 @@
*/ */
/* Defines MAC-layer interface to LLC layer */ /* Defines MAC-layer interface to LLC layer */
extern int mac_send_pdu(struct sk_buff *skb); extern int mac_send_pdu(struct sk_buff *skb);
extern int mac_indicate(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 struct net_device *mac_dev_peer(struct net_device *current_dev, extern struct net_device *mac_dev_peer(struct net_device *current_dev,
int type, u8 *mac); int type, u8 *mac);
extern int llc_pdu_router(struct llc_sap *sap, struct sock *sk,
struct sk_buff *skb, u8 type);
extern u16 lan_hdrs_init(struct sk_buff *skb, u8 *sa, u8 *da); extern u16 lan_hdrs_init(struct sk_buff *skb, u8 *sa, u8 *da);
extern int llc_conn_rcv(struct sock *sk, struct sk_buff *skb);
static __inline__ void llc_set_backlog_type(struct sk_buff *skb, char type) static __inline__ void llc_set_backlog_type(struct sk_buff *skb, char type)
{ {
...@@ -31,4 +30,36 @@ static __inline__ char llc_backlog_type(struct sk_buff *skb) ...@@ -31,4 +30,36 @@ static __inline__ char llc_backlog_type(struct sk_buff *skb)
return skb->cb[sizeof(skb->cb) - 1]; return skb->cb[sizeof(skb->cb) - 1];
} }
extern u8 llc_mac_null_var[IFHWADDRLEN];
/**
* llc_mac_null - determines if a address is a null mac address
* @mac: Mac address to test if null.
*
* Determines if a given address is a null mac address. Returns 0 if the
* address is not a null mac, 1 if the address is a null mac.
*/
static __inline__ int llc_mac_null(u8 *mac)
{
return !memcmp(mac, llc_mac_null_var, IFHWADDRLEN);
}
static __inline__ int llc_addrany(struct llc_addr *addr)
{
return llc_mac_null(addr->mac) && !addr->lsap;
}
/**
* llc_mac_match - determines if two mac addresses are the same
* @mac1: First mac address to compare.
* @mac2: Second mac address to compare.
*
* Determines if two given mac address are the same. Returns 0 if there
* is not a complete match up to len, 1 if a complete match up to len is
* found.
*/
static __inline__ int llc_mac_match(u8 *mac1, u8 *mac2)
{
return !memcmp(mac1, mac2, IFHWADDRLEN);
}
#endif /* LLC_MAC_H */ #endif /* LLC_MAC_H */
...@@ -61,8 +61,8 @@ extern void llc_sap_save(struct llc_sap *sap); ...@@ -61,8 +61,8 @@ extern void llc_sap_save(struct llc_sap *sap);
extern void llc_free_sap(struct llc_sap *sap); extern void llc_free_sap(struct llc_sap *sap);
extern struct llc_sap *llc_sap_find(u8 lsap); extern struct llc_sap *llc_sap_find(u8 lsap);
extern struct llc_station *llc_station_get(void); extern struct llc_station *llc_station_get(void);
extern void llc_station_send_ev(struct llc_station *station, extern void llc_station_state_process(struct llc_station *station,
struct sk_buff *skb); struct sk_buff *skb);
extern void llc_station_send_pdu(struct llc_station *station, extern void llc_station_send_pdu(struct llc_station *station,
struct sk_buff *skb); struct sk_buff *skb);
extern struct sk_buff *llc_alloc_frame(void); extern struct sk_buff *llc_alloc_frame(void);
......
...@@ -237,35 +237,35 @@ struct llc_frmr_info { ...@@ -237,35 +237,35 @@ struct llc_frmr_info {
extern void llc_pdu_set_cmd_rsp(struct sk_buff *skb, u8 type); extern void llc_pdu_set_cmd_rsp(struct sk_buff *skb, u8 type);
extern void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value); extern void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value);
extern int llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit); extern void llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit);
extern int llc_pdu_decode_cr_bit(struct sk_buff *skb, u8 *cr_bit); extern void llc_pdu_decode_cr_bit(struct sk_buff *skb, u8 *cr_bit);
extern int llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa); extern void llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa);
extern int llc_pdu_decode_da(struct sk_buff *skb, u8 *ds); extern void llc_pdu_decode_da(struct sk_buff *skb, u8 *ds);
extern int llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap); extern void llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap);
extern int llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap); extern void llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap);
extern int llc_decode_pdu_type(struct sk_buff *skb, u8 *destination); extern void llc_decode_pdu_type(struct sk_buff *skb, u8 *destination);
extern void llc_pdu_header_init(struct sk_buff *skb, u8 pdu_type, u8 ssap, extern void llc_pdu_header_init(struct sk_buff *skb, u8 pdu_type, u8 ssap,
u8 dsap, u8 cr); u8 dsap, u8 cr);
extern int llc_pdu_init_as_ui_cmd(struct sk_buff *skb); extern void llc_pdu_init_as_ui_cmd(struct sk_buff *skb);
extern int llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported, extern void llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported,
u8 rx_window); u8 rx_window);
extern int llc_pdu_init_as_test_cmd(struct sk_buff *skb); extern void llc_pdu_init_as_test_cmd(struct sk_buff *skb);
extern int llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit); extern void llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit);
extern int llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr); extern void llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr);
extern int llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr); extern void llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr);
extern int llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr); extern void llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr);
extern int llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr); extern void llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr);
extern int llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit); extern void llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit);
extern int llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit); extern void llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit);
extern int llc_pdu_init_as_xid_rsp(struct sk_buff *skb, u8 svcs_supported, extern void llc_pdu_init_as_xid_rsp(struct sk_buff *skb, u8 svcs_supported,
u8 rx_window); u8 rx_window);
extern int llc_pdu_init_as_test_rsp(struct sk_buff *skb, extern void llc_pdu_init_as_test_rsp(struct sk_buff *skb,
struct sk_buff *ev_skb); struct sk_buff *ev_skb);
extern int llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, extern void llc_pdu_init_as_frmr_rsp(struct sk_buff *skb,
struct llc_pdu_sn *prev_pdu, struct llc_pdu_sn *prev_pdu,
u8 f_bit, u8 vs, u8 vr, u8 vzyxw); u8 f_bit, u8 vs, u8 vr, u8 vzyxw);
extern int llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr); extern void llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr);
extern int llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr); extern void llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr);
extern int llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr); extern void llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr);
extern int llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit); extern void llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit);
#endif /* LLC_PDU_H */ #endif /* LLC_PDU_H */
...@@ -18,7 +18,6 @@ ...@@ -18,7 +18,6 @@
* @p_bit - only lowest-order bit used * @p_bit - only lowest-order bit used
* @f_bit - only lowest-order bit used * @f_bit - only lowest-order bit used
* @req - provided by LLC layer * @req - provided by LLC layer
* @resp - provided by LLC layer
* @ind - provided by network layer * @ind - provided by network layer
* @conf - provided by network layer * @conf - provided by network layer
* @laddr - SAP value in this 'lsap' * @laddr - SAP value in this 'lsap'
...@@ -31,8 +30,6 @@ struct llc_sap { ...@@ -31,8 +30,6 @@ struct llc_sap {
u8 state; u8 state;
u8 p_bit; u8 p_bit;
u8 f_bit; u8 f_bit;
llc_prim_call_t req;
llc_prim_call_t resp;
llc_prim_call_t ind; llc_prim_call_t ind;
llc_prim_call_t conf; llc_prim_call_t conf;
struct llc_prim_if_block llc_ind_prim, llc_cfm_prim; struct llc_prim_if_block llc_ind_prim, llc_cfm_prim;
...@@ -49,7 +46,7 @@ struct llc_sap_state_ev; ...@@ -49,7 +46,7 @@ struct llc_sap_state_ev;
extern void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk); extern void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk);
extern void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk); extern void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk);
extern void llc_sap_send_ev(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_sap_send_pdu(struct llc_sap *sap, struct sk_buff *skb); extern void llc_sap_send_pdu(struct llc_sap *sap, struct sk_buff *skb);
#endif /* LLC_SAP_H */ #endif /* LLC_SAP_H */
...@@ -134,7 +134,7 @@ int llc_station_ac_report_status(struct llc_station *station, ...@@ -134,7 +134,7 @@ int llc_station_ac_report_status(struct llc_station *station,
static void llc_station_ack_tmr_callback(unsigned long timeout_data) static void llc_station_ack_tmr_callback(unsigned long timeout_data)
{ {
struct llc_station *station = (struct llc_station *)timeout_data; struct llc_station *station = (struct llc_station *)timeout_data;
struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC); struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
station->ack_tmr_running = 0; station->ack_tmr_running = 0;
if (skb) { if (skb) {
...@@ -142,6 +142,6 @@ static void llc_station_ack_tmr_callback(unsigned long timeout_data) ...@@ -142,6 +142,6 @@ static void llc_station_ack_tmr_callback(unsigned long timeout_data)
ev->type = LLC_STATION_EV_TYPE_ACK_TMR; ev->type = LLC_STATION_EV_TYPE_ACK_TMR;
ev->data.tmr.timer_specific = NULL; ev->data.tmr.timer_specific = NULL;
llc_station_send_ev(station, skb); llc_station_state_process(station, skb);
} }
} }
...@@ -65,24 +65,14 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb) ...@@ -65,24 +65,14 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb)
sap = llc_sap_find(dsap); sap = llc_sap_find(dsap);
if (sap) { if (sap) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
struct llc_prim_if_block *prim = &sap->llc_ind_prim;
union llc_u_prim_data *prim_data = prim->data;
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
prim_data->conn.daddr.lsap = dsap;
llc_pdu_decode_sa(skb, llc->daddr.mac); llc_pdu_decode_sa(skb, llc->daddr.mac);
llc_pdu_decode_da(skb, llc->laddr.mac); llc_pdu_decode_da(skb, llc->laddr.mac);
llc->dev = skb->dev; llc->dev = skb->dev;
prim_data->conn.pri = 0; /* FIXME: find better way to notify upper layer */
prim_data->conn.sk = sk; ev->flag = LLC_CONN_PRIM + 1;
prim_data->conn.dev = skb->dev; ev->ind_prim = (void *)1;
memcpy(&prim_data->conn.daddr, &llc->laddr, sizeof(llc->laddr));
memcpy(&prim_data->conn.saddr, &llc->daddr, sizeof(llc->daddr));
prim->data = prim_data;
prim->prim = LLC_CONN_PRIM;
prim->sap = llc->sap;
ev->flag = 1;
ev->ind_prim = prim;
rc = 0; rc = 0;
} }
return rc; return rc;
...@@ -91,42 +81,22 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb) ...@@ -91,42 +81,22 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb)
int llc_conn_ac_conn_confirm(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_conn_confirm(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap;
struct llc_prim_if_block *prim = &sap->llc_cfm_prim;
union llc_u_prim_data *prim_data = prim->data;
prim_data->conn.sk = sk; ev->flag = LLC_CONN_PRIM + 1;
prim_data->conn.pri = 0; ev->cfm_prim = (void *)1;
prim_data->conn.status = ev->status;
prim_data->conn.link = llc->link;
prim_data->conn.dev = skb->dev;
prim->data = prim_data;
prim->prim = LLC_CONN_PRIM;
prim->sap = sap;
ev->flag = 1;
ev->cfm_prim = prim;
return 0; return 0;
} }
static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *skb) static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap;
struct llc_prim_if_block *prim = &sap->llc_cfm_prim;
union llc_u_prim_data *prim_data = prim->data;
prim_data->data.sk = sk; /*
prim_data->data.pri = 0; * FIXME: find better way to tell upper layer that the packet was
prim_data->data.link = llc->link; * confirmed by the other endpoint
prim_data->data.status = LLC_STATUS_RECEIVED; */
prim_data->data.skb = NULL; ev->flag = LLC_DATA_PRIM + 1;
prim->data = prim_data; ev->cfm_prim = (void *)1;
prim->prim = LLC_DATA_PRIM;
prim->sap = sap;
ev->flag = 1;
ev->cfm_prim = prim;
return 0; return 0;
} }
...@@ -164,19 +134,15 @@ int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb) ...@@ -164,19 +134,15 @@ int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb)
rc = 1; rc = 1;
} }
if (!rc) { if (!rc) {
struct llc_opt *llc = llc_sk(sk); /*
struct llc_sap *sap = llc->sap; * FIXME: ev needs reason field,
struct llc_prim_if_block *prim = &sap->llc_ind_prim; * perhaps the ev->status is enough,
union llc_u_prim_data *prim_data = prim->data; * have to check,
* better way to signal its a disc
prim_data->disc.sk = sk; */
prim_data->disc.reason = reason; /* prim_data->disc.reason = reason; */
prim_data->disc.link = llc->link; ev->flag = LLC_DISC_PRIM + 1;
prim->data = prim_data; ev->ind_prim = (void *)1;
prim->prim = LLC_DISC_PRIM;
prim->sap = llc->sap;
ev->flag = 1;
ev->ind_prim = prim;
} }
return rc; return rc;
} }
...@@ -184,19 +150,11 @@ int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb) ...@@ -184,19 +150,11 @@ int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb)
int llc_conn_ac_disc_confirm(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_disc_confirm(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap;
struct llc_prim_if_block *prim = &sap->llc_cfm_prim;
union llc_u_prim_data *prim_data = prim->data;
prim_data->disc.sk = sk; /* here we use the ev->status, humm */
prim_data->disc.reason = ev->status; /* prim_data->disc.reason = ev->status; */
prim_data->disc.link = llc->link; ev->flag = LLC_DISC_PRIM + 1;
prim->data = prim_data; ev->cfm_prim = (void *)1;
prim->prim = LLC_DISC_PRIM;
prim->sap = sap;
ev->flag = 1;
ev->cfm_prim = prim;
return 0; return 0;
} }
...@@ -1342,12 +1300,15 @@ int llc_conn_ac_upd_nr_received(struct sock *sk, struct sk_buff *skb) ...@@ -1342,12 +1300,15 @@ int llc_conn_ac_upd_nr_received(struct sock *sk, struct sk_buff *skb)
int llc_conn_ac_upd_p_flag(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_upd_p_flag(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
u8 f_bit;
if (!LLC_PDU_IS_RSP(pdu) && if (!LLC_PDU_IS_RSP(pdu)) {
!llc_pdu_decode_pf_bit(skb, &f_bit) && f_bit) { u8 f_bit;
llc_sk(sk)->p_flag = 0;
llc_conn_ac_stop_p_timer(sk, skb); llc_pdu_decode_pf_bit(skb, &f_bit);
if (f_bit) {
llc_sk(sk)->p_flag = 0;
llc_conn_ac_stop_p_timer(sk, skb);
}
} }
return 0; return 0;
} }
...@@ -1459,61 +1420,73 @@ int llc_conn_ac_set_f_flag_p(struct sock *sk, struct sk_buff *skb) ...@@ -1459,61 +1420,73 @@ int llc_conn_ac_set_f_flag_p(struct sock *sk, struct sk_buff *skb)
void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data) void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data)
{ {
struct sock *sk = (struct sock *)timeout_data; struct sock *sk = (struct sock *)timeout_data;
struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC); struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
bh_lock_sock(sk);
llc_sk(sk)->pf_cycle_timer.running = 0; llc_sk(sk)->pf_cycle_timer.running = 0;
if (skb) { if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
skb->sk = sk;
ev->type = LLC_CONN_EV_TYPE_P_TMR; ev->type = LLC_CONN_EV_TYPE_P_TMR;
ev->data.tmr.timer_specific = NULL; ev->data.tmr.timer_specific = NULL;
llc_process_tmr_ev(sk, skb); llc_process_tmr_ev(sk, skb);
} }
bh_unlock_sock(sk);
} }
static void llc_conn_busy_tmr_cb(unsigned long timeout_data) static void llc_conn_busy_tmr_cb(unsigned long timeout_data)
{ {
struct sock *sk = (struct sock *)timeout_data; struct sock *sk = (struct sock *)timeout_data;
struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC); struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
bh_lock_sock(sk);
llc_sk(sk)->busy_state_timer.running = 0; llc_sk(sk)->busy_state_timer.running = 0;
if (skb) { if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
skb->sk = sk;
ev->type = LLC_CONN_EV_TYPE_BUSY_TMR; ev->type = LLC_CONN_EV_TYPE_BUSY_TMR;
ev->data.tmr.timer_specific = NULL; ev->data.tmr.timer_specific = NULL;
llc_process_tmr_ev(sk, skb); llc_process_tmr_ev(sk, skb);
} }
bh_unlock_sock(sk);
} }
void llc_conn_ack_tmr_cb(unsigned long timeout_data) void llc_conn_ack_tmr_cb(unsigned long timeout_data)
{ {
struct sock* sk = (struct sock *)timeout_data; struct sock* sk = (struct sock *)timeout_data;
struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC); struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
bh_lock_sock(sk);
llc_sk(sk)->ack_timer.running = 0; llc_sk(sk)->ack_timer.running = 0;
if (skb) { if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
skb->sk = sk;
ev->type = LLC_CONN_EV_TYPE_ACK_TMR; ev->type = LLC_CONN_EV_TYPE_ACK_TMR;
ev->data.tmr.timer_specific = NULL; ev->data.tmr.timer_specific = NULL;
llc_process_tmr_ev(sk, skb); llc_process_tmr_ev(sk, skb);
} }
bh_unlock_sock(sk);
} }
static void llc_conn_rej_tmr_cb(unsigned long timeout_data) static void llc_conn_rej_tmr_cb(unsigned long timeout_data)
{ {
struct sock *sk = (struct sock *)timeout_data; struct sock *sk = (struct sock *)timeout_data;
struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC); struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
bh_lock_sock(sk);
llc_sk(sk)->rej_sent_timer.running = 0; llc_sk(sk)->rej_sent_timer.running = 0;
if (skb) { if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
skb->sk = sk;
ev->type = LLC_CONN_EV_TYPE_REJ_TMR; ev->type = LLC_CONN_EV_TYPE_REJ_TMR;
ev->data.tmr.timer_specific = NULL; ev->data.tmr.timer_specific = NULL;
llc_process_tmr_ev(sk, skb); llc_process_tmr_ev(sk, skb);
} }
bh_unlock_sock(sk);
} }
int llc_conn_ac_rst_vs(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_rst_vs(struct sock *sk, struct sk_buff *skb)
...@@ -1541,14 +1514,11 @@ int llc_conn_ac_upd_vs(struct sock *sk, struct sk_buff *skb) ...@@ -1541,14 +1514,11 @@ int llc_conn_ac_upd_vs(struct sock *sk, struct sk_buff *skb)
* llc_conn_disc - removes connection from SAP list and frees it * llc_conn_disc - removes connection from SAP list and frees it
* @sk: closed connection * @sk: closed connection
* @skb: occurred event * @skb: occurred event
*
* Returns 2, to indicate the state machine that the connection was freed.
*/ */
int llc_conn_disc(struct sock *sk, struct sk_buff *skb) int llc_conn_disc(struct sock *sk, struct sk_buff *skb)
{ {
llc_sap_unassign_sock(llc_sk(sk)->sap, sk); /* FIXME: this thing seems to want to die */
llc_sock_free(sk); return 0;
return 2;
} }
/** /**
...@@ -1560,7 +1530,7 @@ int llc_conn_disc(struct sock *sk, struct sk_buff *skb) ...@@ -1560,7 +1530,7 @@ int llc_conn_disc(struct sock *sk, struct sk_buff *skb)
*/ */
int llc_conn_reset(struct sock *sk, struct sk_buff *skb) int llc_conn_reset(struct sock *sk, struct sk_buff *skb)
{ {
llc_sock_reset(sk); llc_sk_reset(sk);
return 0; return 0;
} }
...@@ -1589,24 +1559,21 @@ u8 llc_circular_between(u8 a, u8 b, u8 c) ...@@ -1589,24 +1559,21 @@ u8 llc_circular_between(u8 a, u8 b, u8 c)
* This function is called from timer callback functions. When connection * This function is called from timer callback functions. When connection
* is busy (during sending a data frame) timer expiration event must be * is busy (during sending a data frame) timer expiration event must be
* queued. Otherwise this event can be sent to connection state machine. * queued. Otherwise this event can be sent to connection state machine.
* Queued events will process by process_rxframes_events function after * Queued events will process by llc_backlog_rcv function after sending
* sending data frame. Returns 0 for success, 1 otherwise. * data frame.
*/ */
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)
{ {
bh_lock_sock(sk);
if (llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) { if (llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) {
printk(KERN_WARNING "%s: timer called on closed connection\n", printk(KERN_WARNING "%s: timer called on closed connection\n",
__FUNCTION__); __FUNCTION__);
llc_conn_free_ev(skb); llc_conn_free_ev(skb);
goto out; } else {
} if (!sk->lock.users)
if (!sk->lock.users) llc_conn_state_process(sk, skb);
llc_conn_send_ev(sk, skb); else {
else { llc_set_backlog_type(skb, LLC_EVENT);
llc_set_backlog_type(skb, LLC_EVENT); sk_add_backlog(sk, skb);
sk_add_backlog(sk, skb); }
} }
out:
bh_unlock_sock(sk);
} }
...@@ -241,9 +241,8 @@ int llc_conn_ev_rx_i_cmd_pbit_set_x_inval_ns(struct sock *sk, ...@@ -241,9 +241,8 @@ int llc_conn_ev_rx_i_cmd_pbit_set_x_inval_ns(struct sock *sk,
u16 rc = !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr && u16 rc = !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr &&
llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1;
if (!rc) if (!rc)
dprintk(KERN_WARNING "rx_i_cmd_p_bit_set_x_inval_ns matched," dprintk("%s: matched, state=%d, ns=%d, vr=%d\n",
"state = %d, ns = %d, vr = %d\n", __FUNCTION__, llc_sk(sk)->state, ns, vr);
llc_sk(sk)->state, ns, vr);
return rc; return rc;
} }
...@@ -317,9 +316,8 @@ int llc_conn_ev_rx_i_rsp_fbit_set_x_inval_ns(struct sock *sk, ...@@ -317,9 +316,8 @@ int llc_conn_ev_rx_i_rsp_fbit_set_x_inval_ns(struct sock *sk,
u16 rc = !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr && u16 rc = !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr &&
llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1;
if (!rc) if (!rc)
dprintk(KERN_WARNING "conn_ev_rx_i_rsp_fbit_set_x_inval_ns " dprintk("%s: matched, state=%d, ns=%d, vr=%d\n",
"matched : state = %d, ns = %d, vr = %d\n", __FUNCTION__, llc_sk(sk)->state, ns, vr);
llc_sk(sk)->state, ns, vr);
return rc; return rc;
} }
...@@ -584,9 +582,8 @@ int llc_conn_ev_rx_zzz_cmd_pbit_set_x_inval_nr(struct sock *sk, ...@@ -584,9 +582,8 @@ int llc_conn_ev_rx_zzz_cmd_pbit_set_x_inval_nr(struct sock *sk,
if (!LLC_PDU_IS_CMD(pdu) && if (!LLC_PDU_IS_CMD(pdu) &&
(!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) && (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) &&
nr != vs && llc_util_nr_inside_tx_window(sk, nr)) { nr != vs && llc_util_nr_inside_tx_window(sk, nr)) {
dprintk(KERN_ERR "conn_ev_rx_zzz_cmd_inv_nr matched, state = " dprintk("%s: matched, state=%d, vs=%d, nr=%d\n",
"%d, vs = %d, nr = %d\n", __FUNCTION__, llc_sk(sk)->state, vs, nr);
llc_sk(sk)->state, vs, nr);
rc = 0; rc = 0;
} }
return rc; return rc;
...@@ -604,9 +601,8 @@ int llc_conn_ev_rx_zzz_rsp_fbit_set_x_inval_nr(struct sock *sk, ...@@ -604,9 +601,8 @@ int llc_conn_ev_rx_zzz_rsp_fbit_set_x_inval_nr(struct sock *sk,
(!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) && (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) &&
nr != vs && llc_util_nr_inside_tx_window(sk, nr)) { nr != vs && llc_util_nr_inside_tx_window(sk, nr)) {
rc = 0; rc = 0;
dprintk(KERN_ERR "conn_ev_rx_zzz_fbit_set_x_inval_nr matched, " dprintk("%s: matched, state=%d, vs=%d, nr=%d\n",
"state = %d, vs = %d, nr = %d\n", __FUNCTION__, llc_sk(sk)->state, vs, nr);
llc_sk(sk)->state, vs, nr);
} }
return rc; return rc;
} }
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <net/llc_sap.h> #include <net/llc_sap.h>
#include <net/llc_conn.h> #include <net/llc_conn.h>
#include <net/sock.h> #include <net/sock.h>
#include <linux/tcp.h>
#include <net/llc_main.h> #include <net/llc_main.h>
#include <net/llc_c_ev.h> #include <net/llc_c_ev.h>
#include <net/llc_c_ac.h> #include <net/llc_c_ac.h>
...@@ -38,65 +39,149 @@ static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk, ...@@ -38,65 +39,149 @@ static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk,
/* Offset table on connection states transition diagram */ /* Offset table on connection states transition diagram */
static int llc_offset_table[NBR_CONN_STATES][NBR_CONN_EV]; static int llc_offset_table[NBR_CONN_STATES][NBR_CONN_EV];
static void llc_save_primitive(struct sock *sk, struct sk_buff* skb,
u8 ua, u8 test, u8 xid)
{
struct llc_opt *llc = llc_sk(sk);
struct sockaddr_llc *addr = llc_ui_skb_cb(skb);
/* save primitive for use by the user. */
addr->sllc_family = sk->family;
addr->sllc_arphrd = skb->dev->type;
addr->sllc_test = test;
addr->sllc_xid = xid;
addr->sllc_ua = ua;
addr->sllc_dsap = llc->sap->laddr.lsap;
memcpy(addr->sllc_dmac, llc->laddr.mac, IFHWADDRLEN);
addr->sllc_ssap = llc->daddr.lsap;
memcpy(addr->sllc_smac, llc->daddr.mac, IFHWADDRLEN);
}
/** /**
* llc_conn_send_event - sends event to connection state machine * llc_conn_state_process - sends event to connection state machine
* @sk: connection * @sk: connection
* @skb: occurred event * @skb: occurred event
* *
* Sends an event to connection state machine. after processing event * Sends an event to connection state machine. After processing event
* (executing it's actions and changing state), upper layer will be * (executing it's actions and changing state), upper layer will be
* indicated or confirmed, if needed. Returns 0 for success, 1 for * indicated or confirmed, if needed. Returns 0 for success, 1 for
* failure. The socket lock has to be held before calling this function. * failure. The socket lock has to be held before calling this function.
*/ */
int llc_conn_send_ev(struct sock *sk, struct sk_buff *skb) int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
{ {
/* sending event to state machine */ /* sending event to state machine */
int rc = llc_conn_service(sk, skb); int rc = llc_conn_service(sk, skb);
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
u8 flag = ev->flag; u8 flag = ev->flag;
u8 status = ev->status;
struct llc_prim_if_block *ind_prim = ev->ind_prim; struct llc_prim_if_block *ind_prim = ev->ind_prim;
struct llc_prim_if_block *cfm_prim = ev->cfm_prim; struct llc_prim_if_block *cfm_prim = ev->cfm_prim;
llc_conn_free_ev(skb); /*
#ifdef THIS_BREAKS_DISCONNECT_NOTIFICATION_BADLY * FIXME: this will vanish as soon I get rid of the last prim crap
/* check if the connection was freed by the state machine by */
* means of llc_conn_disc */ if (flag != LLC_DATA_PRIM + 1 && flag != LLC_CONN_PRIM + 1 &&
if (rc == 2) { flag != LLC_DISC_PRIM + 1)
printk(KERN_INFO "%s: rc == 2\n", __FUNCTION__); llc_conn_free_ev(skb);
rc = -ECONNABORTED; else if (ind_prim && cfm_prim)
goto out; skb_get(skb);
}
#endif /* THIS_BREAKS_DISCONNECT_NOTIFICATION_BADLY */
if (!flag) /* indicate or confirm not required */ if (!flag) /* indicate or confirm not required */
goto out; goto out;
rc = 0; rc = 0;
if (ind_prim) /* indication required */ if (ind_prim) { /* indication required */
llc->sap->ind(ind_prim); /*
* FIXME: this will be saner as soon I get rid of the double
* sock crap
*/
switch (flag) {
case LLC_DATA_PRIM + 1:
llc_save_primitive(sk, skb, 0, 0, 0);
if (sock_queue_rcv_skb(sk, skb)) {
/*
* FIXME: have to sync the LLC state
* machine wrt mem usage with
* sk->{r,w}mem_alloc, will do
* this soon 8)
*/
printk(KERN_ERR
"%s: sock_queue_rcv_skb failed!\n",
__FUNCTION__);
kfree_skb(skb);
}
break;
case LLC_CONN_PRIM + 1: {
struct sock *parent = skb->sk;
skb->sk = sk;
skb_queue_tail(&parent->receive_queue, skb);
sk->state_change(parent);
}
break;
case LLC_DISC_PRIM + 1:
sock_hold(sk);
if (sk->type == SOCK_STREAM && sk->state == TCP_ESTABLISHED) {
sk->shutdown = SHUTDOWN_MASK;
sk->socket->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE;
if (!sk->dead) {
sk->state_change(sk);
sk->dead = 1;
}
}
kfree_skb(skb);
sock_put(sk);
break;
default:
llc->sap->ind(ind_prim);
}
}
if (!cfm_prim) /* confirmation not required */ if (!cfm_prim) /* confirmation not required */
goto out; goto out;
/* data confirm has preconditions */ /* FIXME: see FIXMEs above */
if (cfm_prim->prim != LLC_DATA_PRIM) { switch (flag) {
case LLC_DATA_PRIM + 1:
if (!llc_data_accept_state(llc->state))
/* In this state, we can send I pdu */
sk->write_space(sk);
else
rc = llc->failed_data_req = 1;
break;
case LLC_CONN_PRIM + 1:
if (sk->type != SOCK_STREAM || sk->state != TCP_SYN_SENT)
goto out_kfree_skb;
if (status) {
sk->socket->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE;
} else {
sk->socket->state = SS_CONNECTED;
sk->state = TCP_ESTABLISHED;
}
sk->state_change(sk);
break;
case LLC_DISC_PRIM + 1:
sock_hold(sk);
if (sk->type != SOCK_STREAM || sk->state != TCP_CLOSING) {
sock_put(sk);
goto out_kfree_skb;
}
sk->socket->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE;
sk->state_change(sk);
sock_put(sk);
break;
default:
llc->sap->conf(cfm_prim); llc->sap->conf(cfm_prim);
goto out; goto out;
} }
if (!llc_data_accept_state(llc->state)) { out_kfree_skb:
/* In this state, we can send I pdu */ kfree_skb(skb);
/* FIXME: check if we don't need to see if sk->lock.users != 0
* is needed here
*/
rc = llc->sap->conf(cfm_prim);
if (rc) /* confirmation didn't accept by upper layer */
llc->failed_data_req = 1;
} else
llc->failed_data_req = 1;
out: out:
return rc; return rc;
} }
void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb) void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb)
{ {
llc_sock_assert(sk);
/* queue PDU to send to MAC layer */ /* queue PDU to send to MAC layer */
skb_queue_tail(&sk->write_queue, skb); skb_queue_tail(&sk->write_queue, skb);
llc_conn_send_pdus(sk); llc_conn_send_pdus(sk);
...@@ -109,26 +194,15 @@ void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb) ...@@ -109,26 +194,15 @@ void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb)
* *
* Sends received data pdu to upper layer (by using indicate function). * Sends received data pdu to upper layer (by using indicate function).
* Prepares service parameters (prim and prim_data). calling indication * Prepares service parameters (prim and prim_data). calling indication
* function will be done in llc_conn_send_ev. * function will be done in llc_conn_state_process.
*/ */
void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb) void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap = llc->sap; /* FIXME: indicate that we should send this to the upper layer */
struct llc_prim_if_block *prim = &sap->llc_ind_prim; ev->flag = LLC_DATA_PRIM + 1;
union llc_u_prim_data *prim_data = prim->data; ev->ind_prim = (void *)1;
prim_data->data.sk = sk;
prim_data->data.pri = 0;
prim_data->data.skb = skb;
prim_data->data.link = llc->link;
prim->data = prim_data;
prim->prim = LLC_DATA_PRIM;
prim->sap = sap;
ev->flag = 1;
/* saving prepd prim in event for future use in llc_conn_send_ev */
ev->ind_prim = prim;
} }
/** /**
...@@ -369,11 +443,10 @@ static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk, ...@@ -369,11 +443,10 @@ static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk,
* llc_exec_conn_trans_actions - executes related actions * llc_exec_conn_trans_actions - executes related actions
* @sk: connection * @sk: connection
* @trans: transition that it's actions must be performed * @trans: transition that it's actions must be performed
* @skb: happened event * @skb: event
* *
* Executes actions that is related to happened event. Returns 0 for * Executes actions that is related to happened event. Returns 0 for
* success, 1 to indicate failure of at least one action or 2 if the * success, 1 to indicate failure of at least one action.
* connection was freed (llc_conn_disc was called)
*/ */
static int llc_exec_conn_trans_actions(struct sock *sk, static int llc_exec_conn_trans_actions(struct sock *sk,
struct llc_conn_state_trans *trans, struct llc_conn_state_trans *trans,
...@@ -396,7 +469,7 @@ static int llc_exec_conn_trans_actions(struct sock *sk, ...@@ -396,7 +469,7 @@ static int llc_exec_conn_trans_actions(struct sock *sk,
} }
/** /**
* llc_find_sock - Finds connection in sap for the remote/local sap/mac * llc_lookup_established - Finds connection for the remote/local sap/mac
* @sap: SAP * @sap: SAP
* @daddr: address of remote LLC (MAC + SAP) * @daddr: address of remote LLC (MAC + SAP)
* @laddr: address of local LLC (MAC + SAP) * @laddr: address of local LLC (MAC + SAP)
...@@ -405,8 +478,8 @@ static int llc_exec_conn_trans_actions(struct sock *sk, ...@@ -405,8 +478,8 @@ static int llc_exec_conn_trans_actions(struct sock *sk,
* mac, remote sap, local mac, and local sap. Returns pointer for * mac, remote sap, local mac, and local sap. Returns pointer for
* connection found, %NULL otherwise. * connection found, %NULL otherwise.
*/ */
struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr, struct sock *llc_lookup_established(struct llc_sap *sap, struct llc_addr *daddr,
struct llc_addr *laddr) struct llc_addr *laddr)
{ {
struct sock *rc = NULL; struct sock *rc = NULL;
struct list_head *entry; struct list_head *entry;
...@@ -419,8 +492,8 @@ struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr, ...@@ -419,8 +492,8 @@ struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr,
if (llc->laddr.lsap == laddr->lsap && if (llc->laddr.lsap == laddr->lsap &&
llc->daddr.lsap == daddr->lsap && llc->daddr.lsap == daddr->lsap &&
!memcmp(llc->laddr.mac, laddr->mac, ETH_ALEN) && llc_mac_match(llc->laddr.mac, laddr->mac) &&
!memcmp(llc->daddr.mac, daddr->mac, ETH_ALEN)) { llc_mac_match(llc->daddr.mac, daddr->mac)) {
rc = llc->sk; rc = llc->sk;
break; break;
} }
...@@ -432,6 +505,39 @@ struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr, ...@@ -432,6 +505,39 @@ struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr,
return rc; return rc;
} }
/**
* llc_lookup_listener - Finds listener for local MAC + SAP
* @sap: SAP
* @laddr: address of local LLC (MAC + SAP)
*
* Search connection list of the SAP and finds connection listening on
* local mac, and local sap. Returns pointer for parent socket found,
* %NULL otherwise.
*/
struct sock *llc_lookup_listener(struct llc_sap *sap, struct llc_addr *laddr)
{
struct sock *rc = NULL;
struct list_head *entry;
spin_lock_bh(&sap->sk_list.lock);
if (list_empty(&sap->sk_list.list))
goto out;
list_for_each(entry, &sap->sk_list.list) {
struct llc_opt *llc = list_entry(entry, struct llc_opt, node);
if (llc->sk->type != SOCK_STREAM || llc->sk->state != TCP_LISTEN ||
llc->laddr.lsap != laddr->lsap ||
!llc_mac_match(llc->laddr.mac, laddr->mac))
continue;
rc = llc->sk;
}
if (rc)
sock_hold(rc);
out:
spin_unlock_bh(&sap->sk_list.lock);
return rc;
}
/** /**
* llc_data_accept_state - designates if in this state data can be sent. * llc_data_accept_state - designates if in this state data can be sent.
* @state: state of connection. * @state: state of connection.
...@@ -440,10 +546,8 @@ struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr, ...@@ -440,10 +546,8 @@ struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr,
*/ */
u8 llc_data_accept_state(u8 state) u8 llc_data_accept_state(u8 state)
{ {
if (state != LLC_CONN_STATE_NORMAL && state != LLC_CONN_STATE_BUSY && return state != LLC_CONN_STATE_NORMAL && state != LLC_CONN_STATE_BUSY &&
state != LLC_CONN_STATE_REJ) state != LLC_CONN_STATE_REJ;
return 1; /* data_conn_refuse */
return 0;
} }
/** /**
......
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/tcp.h>
#include <asm/errno.h> #include <asm/errno.h>
#include <net/llc_if.h> #include <net/llc_if.h>
#include <net/llc_sap.h> #include <net/llc_sap.h>
...@@ -27,42 +28,6 @@ ...@@ -27,42 +28,6 @@
#include <net/llc_main.h> #include <net/llc_main.h>
#include <net/llc_mac.h> #include <net/llc_mac.h>
static int llc_sap_req(struct llc_prim_if_block *prim);
static int llc_unitdata_req_handler(struct llc_prim_if_block *prim);
static int llc_test_req_handler(struct llc_prim_if_block *prim);
static int llc_xid_req_handler(struct llc_prim_if_block *prim);
static int llc_data_req_handler(struct llc_prim_if_block *prim);
static int llc_conn_req_handler(struct llc_prim_if_block *prim);
static int llc_disc_req_handler(struct llc_prim_if_block *prim);
static int llc_rst_req_handler(struct llc_prim_if_block *prim);
static int llc_flowcontrol_req_handler(struct llc_prim_if_block *prim);
static int llc_sap_resp(struct llc_prim_if_block *prim);
static int llc_conn_rsp_handler(struct llc_prim_if_block *prim);
static int llc_rst_rsp_handler(struct llc_prim_if_block *prim);
static int llc_no_rsp_handler(struct llc_prim_if_block *prim);
/* table of request handler functions */
static llc_prim_call_t llc_req_prim[LLC_NBR_PRIMITIVES] = {
[LLC_DATAUNIT_PRIM] = llc_unitdata_req_handler,
[LLC_CONN_PRIM] = llc_conn_req_handler,
[LLC_DATA_PRIM] = llc_data_req_handler,
[LLC_DISC_PRIM] = llc_disc_req_handler,
[LLC_RESET_PRIM] = llc_rst_req_handler,
[LLC_FLOWCONTROL_PRIM] = llc_flowcontrol_req_handler,
[LLC_XID_PRIM] = llc_xid_req_handler,
[LLC_TEST_PRIM] = llc_test_req_handler,
};
/* table of response handler functions */
static llc_prim_call_t llc_resp_prim[LLC_NBR_PRIMITIVES] = {
[LLC_DATAUNIT_PRIM] = llc_no_rsp_handler,
[LLC_CONN_PRIM] = llc_conn_rsp_handler,
[LLC_DATA_PRIM] = llc_no_rsp_handler,
[LLC_DISC_PRIM] = llc_no_rsp_handler,
[LLC_RESET_PRIM] = llc_rst_rsp_handler,
[LLC_FLOWCONTROL_PRIM] = llc_no_rsp_handler,
};
/** /**
* llc_sap_open - open interface to the upper layers. * llc_sap_open - open interface to the upper layers.
* @nw_indicate: pointer to indicate function of upper layer. * @nw_indicate: pointer to indicate function of upper layer.
...@@ -70,7 +35,7 @@ static llc_prim_call_t llc_resp_prim[LLC_NBR_PRIMITIVES] = { ...@@ -70,7 +35,7 @@ static llc_prim_call_t llc_resp_prim[LLC_NBR_PRIMITIVES] = {
* @lsap: SAP number. * @lsap: SAP number.
* @sap: pointer to allocated SAP (output argument). * @sap: pointer to allocated SAP (output argument).
* *
* Interface function to upper layer. each one who wants to get a SAP * Interface function to upper layer. Each one who wants to get a SAP
* (for example NetBEUI) should call this function. Returns the opened * (for example NetBEUI) should call this function. Returns the opened
* SAP for success, NULL for failure. * SAP for success, NULL for failure.
*/ */
...@@ -92,8 +57,6 @@ struct llc_sap *llc_sap_open(llc_prim_call_t nw_indicate, ...@@ -92,8 +57,6 @@ struct llc_sap *llc_sap_open(llc_prim_call_t nw_indicate,
goto err; goto err;
/* allocated a SAP; initialize it and clear out its memory pool */ /* allocated a SAP; initialize it and clear out its memory pool */
sap->laddr.lsap = lsap; sap->laddr.lsap = lsap;
sap->req = llc_sap_req;
sap->resp = llc_sap_resp;
sap->ind = nw_indicate; sap->ind = nw_indicate;
sap->conf = nw_confirm; sap->conf = nw_confirm;
sap->parent_station = llc_station_get(); sap->parent_station = llc_station_get();
...@@ -110,7 +73,7 @@ struct llc_sap *llc_sap_open(llc_prim_call_t nw_indicate, ...@@ -110,7 +73,7 @@ struct llc_sap *llc_sap_open(llc_prim_call_t nw_indicate,
* llc_sap_close - close interface for upper layers. * llc_sap_close - close interface for upper layers.
* @sap: SAP to be closed. * @sap: SAP to be closed.
* *
* Close interface function to upper layer. each one who wants to * Close interface function to upper layer. Each one who wants to
* close an open SAP (for example NetBEUI) should call this function. * close an open SAP (for example NetBEUI) should call this function.
*/ */
void llc_sap_close(struct llc_sap *sap) void llc_sap_close(struct llc_sap *sap)
...@@ -120,142 +83,135 @@ void llc_sap_close(struct llc_sap *sap) ...@@ -120,142 +83,135 @@ void llc_sap_close(struct llc_sap *sap)
} }
/** /**
* llc_sap_req - Request interface for upper layers * llc_build_and_send_ui_pkt - unitdata request interface for upper layers
* @prim: pointer to structure that contains service parameters. * @sap: sap to use
* @skb: packet to send
* @addr: destination address
* *
* Request interface function to upper layer. each one who wants to * Upper layers calls this function when upper layer wants to send data
* request a service from LLC, must call this function. details of * using connection-less mode communication (UI pdu).
* requested service is defined in input argument(prim). Returns 0 for *
* success, 1 otherwise. * 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
*/ */
static int llc_sap_req(struct llc_prim_if_block *prim) void llc_build_and_send_ui_pkt(struct llc_sap *sap,
struct sk_buff *skb,
struct sockaddr_llc *addr)
{ {
int rc = 1; union llc_u_prim_data prim_data;
struct llc_prim_if_block prim;
struct llc_sap_state_ev *ev = llc_sap_ev(skb);
if (prim->prim > 8 || prim->prim == 6) { skb->protocol = llc_proto_type(addr->sllc_arphrd);
printk(KERN_ERR "%s: invalid primitive %d\n", __FUNCTION__,
prim->prim);
goto out;
}
/* receive REQUEST primitive from network layer; call the appropriate
* primitive handler which then packages it up as an event and sends it
* to the SAP or CONNECTION event handler
*/
if (prim->prim < LLC_NBR_PRIMITIVES)
/* valid primitive; call the function to handle it */
rc = llc_req_prim[prim->prim](prim);
out:
return rc;
}
/** prim.data = &prim_data;
* llc_unitdata_req_handler - unitdata request interface for upper layers prim.sap = sap;
* @prim: pointer to structure that contains service parameters prim.prim = LLC_DATAUNIT_PRIM;
*
* Upper layers calls this function when upper layer wants to send data prim_data.udata.skb = skb;
* using connection-less mode communication (UI pdu). Returns 0 for prim_data.udata.saddr.lsap = sap->laddr.lsap;
* success, 1 otherwise. prim_data.udata.daddr.lsap = addr->sllc_dsap;
*/ memcpy(prim_data.udata.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
static int llc_unitdata_req_handler(struct llc_prim_if_block *prim) memcpy(prim_data.udata.daddr.mac, addr->sllc_dmac, IFHWADDRLEN);
{
int rc = 1;
struct llc_sap_state_ev *ev;
/* 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
*/
struct llc_sap *sap = llc_sap_find(prim->data->udata.saddr.lsap);
if (!sap)
goto out;
ev = llc_sap_ev(prim->data->udata.skb);
ev->type = LLC_SAP_EV_TYPE_PRIM; ev->type = LLC_SAP_EV_TYPE_PRIM;
ev->data.prim.prim = LLC_DATAUNIT_PRIM; ev->data.prim.prim = LLC_DATAUNIT_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_REQ; ev->data.prim.type = LLC_PRIM_TYPE_REQ;
ev->data.prim.data = prim; ev->data.prim.data = &prim;
rc = 0; llc_sap_state_process(sap, skb);
llc_sap_send_ev(sap, prim->data->udata.skb);
out:
return rc;
} }
/** /**
* llc_test_req_handler - TEST interface for upper layers. * llc_build_and_send_test_pkt - TEST interface for upper layers.
* @prim: pointer to structure that contains service parameters. * @sap: sap to use
* @skb: packet to send
* @addr: destination address
* *
* This function is called when upper layer wants to send a TEST pdu. * This function is called when upper layer wants to send a TEST pdu.
* Returns 0 for success, 1 otherwise. * Returns 0 for success, 1 otherwise.
*/ */
static int llc_test_req_handler(struct llc_prim_if_block *prim) void llc_build_and_send_test_pkt(struct llc_sap *sap,
struct sk_buff *skb,
struct sockaddr_llc *addr)
{ {
int rc = 1; union llc_u_prim_data prim_data;
struct llc_sap_state_ev *ev; struct llc_prim_if_block prim;
/* package primitive as an event and send to SAP event handler */ struct llc_sap_state_ev *ev = llc_sap_ev(skb);
struct llc_sap *sap = llc_sap_find(prim->data->udata.saddr.lsap);
if (!sap) skb->protocol = llc_proto_type(addr->sllc_arphrd);
goto out;
ev = llc_sap_ev(prim->data->udata.skb); prim.data = &prim_data;
prim.sap = sap;
prim.prim = LLC_TEST_PRIM;
prim_data.test.skb = skb;
prim_data.test.saddr.lsap = sap->laddr.lsap;
prim_data.test.daddr.lsap = addr->sllc_dsap;
memcpy(prim_data.test.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
memcpy(prim_data.test.daddr.mac, addr->sllc_dmac, IFHWADDRLEN);
ev->type = LLC_SAP_EV_TYPE_PRIM; ev->type = LLC_SAP_EV_TYPE_PRIM;
ev->data.prim.prim = LLC_TEST_PRIM; ev->data.prim.prim = LLC_TEST_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_REQ; ev->data.prim.type = LLC_PRIM_TYPE_REQ;
ev->data.prim.data = prim; ev->data.prim.data = &prim;
rc = 0; llc_sap_state_process(sap, skb);
llc_sap_send_ev(sap, prim->data->udata.skb);
out:
return rc;
} }
/** /**
* llc_xid_req_handler - XID interface for upper layers * llc_build_and_send_xid_pkt - XID interface for upper layers
* @prim: pointer to structure that contains service parameters. * @sap: sap to use
* @skb: packet to send
* @addr: destination address
* *
* This function is called when upper layer wants to send a XID pdu. * This function is called when upper layer wants to send a XID pdu.
* Returns 0 for success, 1 otherwise. * Returns 0 for success, 1 otherwise.
*/ */
static int llc_xid_req_handler(struct llc_prim_if_block *prim) void llc_build_and_send_xid_pkt(struct llc_sap *sap,
struct sk_buff *skb,
struct sockaddr_llc *addr)
{ {
int rc = 1; union llc_u_prim_data prim_data;
struct llc_sap_state_ev *ev; struct llc_prim_if_block prim;
/* package primitive as an event and send to SAP event handler */ struct llc_sap_state_ev *ev = llc_sap_ev(skb);
struct llc_sap *sap = llc_sap_find(prim->data->udata.saddr.lsap);
skb->protocol = llc_proto_type(addr->sllc_arphrd);
prim.data = &prim_data;
prim.sap = sap;
prim.prim = LLC_XID_PRIM;
prim_data.xid.skb = skb;
prim_data.xid.saddr.lsap = sap->laddr.lsap;
prim_data.xid.daddr.lsap = addr->sllc_dsap;
memcpy(prim_data.xid.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
memcpy(prim_data.xid.daddr.mac, addr->sllc_dmac, IFHWADDRLEN);
if (!sap)
goto out;
ev = llc_sap_ev(prim->data->udata.skb);
ev->type = LLC_SAP_EV_TYPE_PRIM; ev->type = LLC_SAP_EV_TYPE_PRIM;
ev->data.prim.prim = LLC_XID_PRIM; ev->data.prim.prim = LLC_XID_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_REQ; ev->data.prim.type = LLC_PRIM_TYPE_REQ;
ev->data.prim.data = prim; ev->data.prim.data = &prim;
rc = 0; llc_sap_state_process(sap, skb);
llc_sap_send_ev(sap, prim->data->udata.skb);
out:
return rc;
} }
/** /**
* llc_data_req_handler - Connection data sending for upper layers. * llc_build_and_send_pkt - Connection data sending for upper layers.
* @prim: pointer to structure that contains service parameters * @prim: pointer to structure that contains service parameters
* *
* This function is called when upper layer wants to send data using * This function is called when upper layer wants to send data using
* connection oriented communication mode. during sending data, connection * connection oriented communication mode. During sending data, connection
* will be locked and received frames and expired timers will be queued. * will be locked and received frames and expired timers will be queued.
* Returns 0 for success, -ECONNABORTED when the connection already * Returns 0 for success, -ECONNABORTED when the connection already
* closed. and -EBUSY when sending data is not permitted in this state or * closed and -EBUSY when sending data is not permitted in this state or
* LLC has send an I pdu with p bit set to 1 and is waiting for it's * LLC has send an I pdu with p bit set to 1 and is waiting for it's
* response. * response.
*/ */
static int llc_data_req_handler(struct llc_prim_if_block *prim) int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb)
{ {
struct llc_conn_state_ev *ev; struct llc_conn_state_ev *ev;
int rc = -ECONNABORTED; int rc = -ECONNABORTED;
/* accept data frame from network layer to be sent using connection
* mode communication; timeout/retries handled by this layer;
* package primitive as an event and send to connection event handler
*/
struct sock *sk = prim->data->data.sk;
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
lock_sock(sk);
if (llc->state == LLC_CONN_STATE_ADM) if (llc->state == LLC_CONN_STATE_ADM)
goto out; goto out;
rc = -EBUSY; rc = -EBUSY;
...@@ -267,169 +223,121 @@ static int llc_data_req_handler(struct llc_prim_if_block *prim) ...@@ -267,169 +223,121 @@ static int llc_data_req_handler(struct llc_prim_if_block *prim)
llc->failed_data_req = 1; llc->failed_data_req = 1;
goto out; goto out;
} }
ev = llc_conn_ev(prim->data->data.skb); ev = llc_conn_ev(skb);
ev->type = LLC_CONN_EV_TYPE_PRIM; ev->type = LLC_CONN_EV_TYPE_PRIM;
ev->data.prim.prim = LLC_DATA_PRIM; ev->data.prim.prim = LLC_DATA_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_REQ; ev->data.prim.type = LLC_PRIM_TYPE_REQ;
ev->data.prim.data = prim; ev->data.prim.data = NULL;
prim->data->data.skb->dev = llc->dev; skb->dev = llc->dev;
rc = llc_conn_send_ev(sk, prim->data->data.skb); rc = llc_conn_state_process(sk, skb);
out: out:
release_sock(sk);
return rc; return rc;
} }
/** /**
* llc_confirm_impossible - Informs upper layer about failed connection * llc_establish_connection - Called by upper layer to establish a conn
* @prim: pointer to structure that contains confirmation data. * @sk: connection
* * @lmac: local mac address
* Informs upper layer about failing in connection establishment. This * @dmac: destination mac address
* function is called by llc_conn_req_handler. * @dsap: destination sap
*/
static void llc_confirm_impossible(struct llc_prim_if_block *prim)
{
prim->data->conn.status = LLC_STATUS_IMPOSSIBLE;
prim->sap->conf(prim);
}
/**
* llc_conn_req_handler - Called by upper layer to establish a conn
* @prim: pointer to structure that contains service parameters.
* *
* Upper layer calls this to establish an LLC connection with a remote * Upper layer calls this to establish an LLC connection with a remote
* machine. this function packages a proper event and sends it connection * machine. This function packages a proper event and sends it connection
* component state machine. Success or failure of connection * component state machine. Success or failure of connection
* establishment will inform to upper layer via calling it's confirm * establishment will inform to upper layer via calling it's confirm
* function and passing proper information. * function and passing proper information.
*/ */
static int llc_conn_req_handler(struct llc_prim_if_block *prim) int llc_establish_connection(struct sock *sk, u8 *lmac, u8 *dmac, u8 dsap)
{ {
int rc = -EBUSY; int rc = -EISCONN;
struct llc_opt *llc;
struct llc_sap *sap = prim->sap;
struct sk_buff *skb;
struct net_device *ddev = mac_dev_peer(prim->data->conn.dev,
prim->data->conn.dev->type,
prim->data->conn.daddr.mac),
*sdev = (ddev->flags & IFF_LOOPBACK) ?
ddev : prim->data->conn.dev;
struct llc_addr laddr, daddr; struct llc_addr laddr, daddr;
/* network layer supplies addressing required to establish connection; struct sk_buff *skb;
* package as an event and send it to the connection event handler struct llc_opt *llc = llc_sk(sk);
*/ struct sock *existing;
struct sock *sk;
laddr.lsap = llc->sap->laddr.lsap;
memcpy(laddr.mac, sdev->dev_addr, sizeof(laddr.mac)); daddr.lsap = dsap;
laddr.lsap = prim->data->conn.saddr.lsap; memcpy(daddr.mac, dmac, sizeof(daddr.mac));
memcpy(daddr.mac, prim->data->conn.daddr.mac, sizeof(daddr.mac)); memcpy(laddr.mac, lmac, sizeof(laddr.mac));
daddr.lsap = prim->data->conn.daddr.lsap; existing = llc_lookup_established(llc->sap, &daddr, &laddr);
sk = llc_find_sock(sap, &daddr, &laddr); if (existing) {
if (sk) { if (existing->state == TCP_ESTABLISHED) {
llc_confirm_impossible(prim); sk = existing;
goto out_put; goto out_put;
} } else
rc = -ENOMEM; sock_put(existing);
if (prim->data->conn.sk) {
sk = prim->data->conn.sk;
if (llc_sock_init(sk))
goto out;
} else {
sk = llc_sock_alloc();
if (!sk) {
llc_confirm_impossible(prim);
goto out;
}
prim->data->conn.sk = sk;
} }
sock_hold(sk); sock_hold(sk);
lock_sock(sk); rc = -ENOMEM;
/* assign new connection to it's SAP */ skb = alloc_skb(0, GFP_ATOMIC);
llc_sap_assign_sock(sap, sk);
llc = llc_sk(sk);
memcpy(&llc->daddr, &daddr, sizeof(llc->daddr));
memcpy(&llc->laddr, &laddr, sizeof(llc->laddr));
llc->dev = ddev;
llc->link = prim->data->conn.link;
llc->handler = prim->data->conn.handler;
skb = alloc_skb(1, GFP_ATOMIC);
if (skb) { if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
ev->type = LLC_CONN_EV_TYPE_PRIM; ev->type = LLC_CONN_EV_TYPE_PRIM;
ev->data.prim.prim = LLC_CONN_PRIM; ev->data.prim.prim = LLC_CONN_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_REQ; ev->data.prim.type = LLC_PRIM_TYPE_REQ;
ev->data.prim.data = prim; ev->data.prim.data = NULL;
rc = llc_conn_send_ev(sk, skb); rc = llc_conn_state_process(sk, skb);
}
if (rc) {
llc_sap_unassign_sock(sap, sk);
llc_sock_free(sk);
llc_confirm_impossible(prim);
} }
release_sock(sk);
out_put: out_put:
sock_put(sk); sock_put(sk);
out:
return rc; return rc;
} }
/** /**
* llc_disc_req_handler - Called by upper layer to close a connection * llc_send_disc - Called by upper layer to close a connection
* @prim: pointer to structure that contains service parameters. * @sk: connection to be closed
* *
* Upper layer calls this when it wants to close an established LLC * Upper layer calls this when it wants to close an established LLC
* connection with a remote machine. this function packages a proper event * connection with a remote machine. This function packages a proper event
* and sends it to connection component state machine. Returns 0 for * and sends it to connection component state machine. Returns 0 for
* success, 1 otherwise. * success, 1 otherwise.
*/ */
static int llc_disc_req_handler(struct llc_prim_if_block *prim) int llc_send_disc(struct sock *sk)
{ {
u16 rc = 1; u16 rc = 1;
struct llc_conn_state_ev *ev; struct llc_conn_state_ev *ev;
struct sk_buff *skb; struct sk_buff *skb;
struct sock* sk = prim->data->disc.sk;
sock_hold(sk); sock_hold(sk);
lock_sock(sk); if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED ||
if (llc_sk(sk)->state == LLC_CONN_STATE_ADM || llc_sk(sk)->state == LLC_CONN_STATE_ADM ||
llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC)
goto out; goto out;
/* /*
* Postpone unassigning the connection from its SAP and returning the * Postpone unassigning the connection from its SAP and returning the
* connection until all ACTIONs have been completely executed * connection until all ACTIONs have been completely executed
*/ */
skb = alloc_skb(1, GFP_ATOMIC); skb = alloc_skb(0, GFP_ATOMIC);
if (!skb) if (!skb)
goto out; goto out;
ev = llc_conn_ev(skb); sk->state = TCP_CLOSING;
ev = llc_conn_ev(skb);
ev->type = LLC_CONN_EV_TYPE_PRIM; ev->type = LLC_CONN_EV_TYPE_PRIM;
ev->data.prim.prim = LLC_DISC_PRIM; ev->data.prim.prim = LLC_DISC_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_REQ; ev->data.prim.type = LLC_PRIM_TYPE_REQ;
ev->data.prim.data = prim; ev->data.prim.data = NULL;
rc = llc_conn_send_ev(sk, skb); rc = llc_conn_state_process(sk, skb);
out: out:
release_sock(sk);
sock_put(sk); sock_put(sk);
return rc; return rc;
} }
/** /**
* llc_rst_req_handler - Resets an established LLC connection * llc_build_and_send_reset_pkt - Resets an established LLC connection
* @prim: pointer to structure that contains service parameters. * @prim: pointer to structure that contains service parameters.
* *
* Called when upper layer wants to reset an established LLC connection * Called when upper layer wants to reset an established LLC connection
* with a remote machine. this function packages a proper event and sends * with a remote machine. This function packages a proper event and sends
* it to connection component state machine. Returns 0 for success, 1 * it to connection component state machine. Returns 0 for success, 1
* otherwise. * otherwise.
*/ */
static int llc_rst_req_handler(struct llc_prim_if_block *prim) int llc_build_and_send_reset_pkt(struct sock *sk,
struct llc_prim_if_block *prim)
{ {
struct sk_buff *skb;
int rc = 1; int rc = 1;
struct sock *sk = prim->data->res.sk; struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
lock_sock(sk);
skb = alloc_skb(1, GFP_ATOMIC);
if (skb) { if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb); struct llc_conn_state_ev *ev = llc_conn_ev(skb);
...@@ -437,87 +345,10 @@ static int llc_rst_req_handler(struct llc_prim_if_block *prim) ...@@ -437,87 +345,10 @@ static int llc_rst_req_handler(struct llc_prim_if_block *prim)
ev->data.prim.prim = LLC_RESET_PRIM; ev->data.prim.prim = LLC_RESET_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_REQ; ev->data.prim.type = LLC_PRIM_TYPE_REQ;
ev->data.prim.data = prim; ev->data.prim.data = prim;
rc = llc_conn_send_ev(sk, skb); rc = llc_conn_state_process(sk, skb);
} }
release_sock(sk);
return rc; return rc;
} }
/* We don't support flow control. The original code from procom has
* some bits, but for now I'm cleaning this
*/
static int llc_flowcontrol_req_handler(struct llc_prim_if_block *prim)
{
return 1;
}
/**
* llc_sap_resp - Sends response to peer
* @prim: pointer to structure that contains service parameters
*
* This function is a interface function to upper layer. each one who
* wants to response to an indicate can call this function via calling
* sap_resp with proper service parameters. Returns 0 for success, 1
* otherwise.
*/
static int llc_sap_resp(struct llc_prim_if_block *prim)
{
u16 rc = 1;
/* network layer RESPONSE primitive received; package primitive
* as an event and send it to the connection event handler
*/
if (prim->prim < LLC_NBR_PRIMITIVES)
/* valid primitive; call the function to handle it */
rc = llc_resp_prim[prim->prim](prim);
return rc;
}
/**
* llc_conn_rsp_handler - Response to connect indication
* @prim: pointer to structure that contains response info.
*
* Response to connect indication.
*/
static int llc_conn_rsp_handler(struct llc_prim_if_block *prim)
{
struct sock *sk = prim->data->conn.sk;
llc_sk(sk)->link = prim->data->conn.link;
return 0;
}
/**
* llc_rst_rsp_handler - Response to RESET indication
* @prim: pointer to structure that contains response info
*
* Returns 0 for success, 1 otherwise
*/
static int llc_rst_rsp_handler(struct llc_prim_if_block *prim)
{
int rc = 1;
/*
* Network layer supplies connection handle; map it to a connection;
* package as event and send it to connection event handler
*/
struct sock *sk = prim->data->res.sk;
struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC);
if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb);
ev->type = LLC_CONN_EV_TYPE_PRIM;
ev->data.prim.prim = LLC_RESET_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_RESP;
ev->data.prim.data = prim;
rc = llc_conn_send_ev(sk, skb);
}
return rc;
}
static int llc_no_rsp_handler(struct llc_prim_if_block *prim)
{
return 0;
}
EXPORT_SYMBOL(llc_sap_open); EXPORT_SYMBOL(llc_sap_open);
EXPORT_SYMBOL(llc_sap_close); EXPORT_SYMBOL(llc_sap_close);
...@@ -27,14 +27,17 @@ ...@@ -27,14 +27,17 @@
#include <net/llc_s_ev.h> #include <net/llc_s_ev.h>
#include <linux/trdevice.h> #include <linux/trdevice.h>
#if 1 #if 0
#define dprintk(args...) printk(KERN_DEBUG args) #define dprintk(args...) printk(KERN_DEBUG args)
#else #else
#define dprintk(args...) #define dprintk(args...)
#endif #endif
/* function prototypes */ u8 llc_mac_null_var[IFHWADDRLEN];
static void fix_up_incoming_skb(struct sk_buff *skb); static void fix_up_incoming_skb(struct sk_buff *skb);
static void llc_station_rcv(struct sk_buff *skb);
static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb);
/** /**
* mac_send_pdu - Sends PDU to specific device. * mac_send_pdu - Sends PDU to specific device.
...@@ -52,7 +55,7 @@ int mac_send_pdu(struct sk_buff *skb) ...@@ -52,7 +55,7 @@ int mac_send_pdu(struct sk_buff *skb)
int pri = GFP_ATOMIC, rc = -1; int pri = GFP_ATOMIC, rc = -1;
if (!skb->dev) { if (!skb->dev) {
dprintk(KERN_ERR "%s: skb->dev == NULL!", __FUNCTION__); dprintk("%s: skb->dev == NULL!", __FUNCTION__);
goto out; goto out;
} }
if (skb->sk) if (skb->sk)
...@@ -67,29 +70,30 @@ int mac_send_pdu(struct sk_buff *skb) ...@@ -67,29 +70,30 @@ int mac_send_pdu(struct sk_buff *skb)
} }
/** /**
* mac_indicate - 802.2 entry point from net lower layers * llc_rcv - 802.2 entry point from net lower layers
* @skb: received pdu * @skb: received pdu
* @dev: device that receive pdu * @dev: device that receive pdu
* @pt: packet type * @pt: packet type
* *
* When the system receives a 802.2 frame this function is called. It * When the system receives a 802.2 frame this function is called. It
* checks SAP and connection of received pdu and passes frame to * checks SAP and connection of received pdu and passes frame to
* llc_pdu_router for sending to proper state machine. If frame is * llc_{station,sap,conn}_rcv for sending to proper state machine. If
* related to a busy connection (a connection is sending data now), * the frame is related to a busy connection (a connection is sending
* function queues this frame in connection's backlog. * data now), it queues this frame in the connection's backlog.
*/ */
int mac_indicate(struct sk_buff *skb, struct net_device *dev, int llc_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt) struct packet_type *pt)
{ {
struct llc_sap *sap; struct llc_sap *sap;
struct llc_pdu_sn *pdu; struct llc_pdu_sn *pdu;
u8 dest; u8 dest;
/* 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 (skb->pkt_type == PACKET_OTHERHOST) {
dprintk(KERN_INFO "%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);
...@@ -98,17 +102,19 @@ int mac_indicate(struct sk_buff *skb, struct net_device *dev, ...@@ -98,17 +102,19 @@ int mac_indicate(struct sk_buff *skb, struct net_device *dev,
fix_up_incoming_skb(skb); fix_up_incoming_skb(skb);
pdu = llc_pdu_sn_hdr(skb); pdu = llc_pdu_sn_hdr(skb);
if (!pdu->dsap) { /* NULL DSAP, refer to station */ if (!pdu->dsap) { /* NULL DSAP, refer to station */
if (llc_pdu_router(NULL, NULL, skb, 0)) dprintk("%s: calling llc_station_rcv!\n", __FUNCTION__);
goto drop; llc_station_rcv(skb);
goto out; goto out;
} }
sap = llc_sap_find(pdu->dsap); sap = llc_sap_find(pdu->dsap);
if (!sap) /* unknown SAP */ if (!sap) {/* unknown SAP */
dprintk("%s: llc_sap_find(%02X) failed!\n", __FUNCTION__, pdu->dsap);
goto drop; goto drop;
}
llc_decode_pdu_type(skb, &dest); llc_decode_pdu_type(skb, &dest);
if (dest == LLC_DEST_SAP) { /* type 1 services */ if (dest == LLC_DEST_SAP) { /* type 1 services */
if (llc_pdu_router(sap, NULL, skb, LLC_TYPE_1)) dprintk("%s: calling llc_sap_rcv!\n", __FUNCTION__);
goto drop; llc_sap_rcv(sap, skb);
} else if (dest == LLC_DEST_CONN) { } else if (dest == LLC_DEST_CONN) {
struct llc_addr saddr, daddr; struct llc_addr saddr, daddr;
struct sock *sk; struct sock *sk;
...@@ -119,34 +125,42 @@ int mac_indicate(struct sk_buff *skb, struct net_device *dev, ...@@ -119,34 +125,42 @@ int mac_indicate(struct sk_buff *skb, struct net_device *dev,
llc_pdu_decode_da(skb, daddr.mac); llc_pdu_decode_da(skb, daddr.mac);
llc_pdu_decode_dsap(skb, &daddr.lsap); llc_pdu_decode_dsap(skb, &daddr.lsap);
sk = llc_find_sock(sap, &saddr, &daddr); sk = llc_lookup_established(sap, &saddr, &daddr);
if (!sk) { /* didn't find an active connection; allocate a if (!sk) {
* connection to use; associate it with this SAP /*
*/ * Didn't find an active connection; verify if there
sk = llc_sock_alloc(); * is a listening socket for this llc addr
if (!sk) */
struct llc_opt *llc;
struct sock *parent;
parent = llc_lookup_listener(sap, &daddr);
if (!parent) {
dprintk("llc_lookup_listener failed!\n");
goto drop;
}
sk = llc_sk_alloc(parent->family, GFP_ATOMIC);
if (!sk) {
sock_put(parent);
goto drop; goto drop;
memcpy(&llc_sk(sk)->daddr, &saddr, sizeof(saddr)); }
llc = llc_sk(sk);
memcpy(&llc->laddr, &daddr, sizeof(llc->laddr));
memcpy(&llc->daddr, &saddr, sizeof(llc->daddr));
llc_sap_assign_sock(sap, sk); llc_sap_assign_sock(sap, sk);
sock_hold(sk); sock_hold(sk);
} sock_put(parent);
skb->sk = parent;
} else
skb->sk = sk;
bh_lock_sock(sk); bh_lock_sock(sk);
if (!sk->lock.users) { if (!sk->lock.users) {
/* FIXME: Check this on SMP as it is now calling /* rc = */ llc_conn_rcv(sk, skb);
* llc_pdu_router _with_ the lock held. rc = 0;
* Old comment:
* With the current code one can't call
* llc_pdu_router with the socket lock held, cause
* it'll route the pdu to the upper layers and it can
* reenter llc and in llc_req_prim will try to grab
* the same lock, maybe we should use spin_trylock_bh
* in the llc_req_prim (llc_data_req_handler, etc) and
* add the request to the backlog, well see...
*/
rc = llc_pdu_router(llc_sk(sk)->sap, sk, skb,
LLC_TYPE_2);
} else { } else {
dprintk(KERN_INFO "%s: add to backlog\n", __FUNCTION__); dprintk("%s: adding to backlog...\n", __FUNCTION__);
llc_set_backlog_type(skb, LLC_PACKET); llc_set_backlog_type(skb, LLC_PACKET);
sk_add_backlog(sk, skb); sk_add_backlog(sk, skb);
rc = 0; rc = 0;
...@@ -191,53 +205,56 @@ static void fix_up_incoming_skb(struct sk_buff *skb) ...@@ -191,53 +205,56 @@ static void fix_up_incoming_skb(struct sk_buff *skb)
} }
} }
/** /*
* llc_pdu_router - routes received pdus to the upper layers * llc_station_rcv - send received pdu to the station state machine
* @sap: current sap component structure. * @skb: received frame.
* @sk: current connection structure.
* @frame: received frame.
* @type: type of received frame, that is LLC_TYPE_1 or LLC_TYPE_2
* *
* Queues received PDUs from LLC_MAC PDU receive queue until queue is * Sends data unit to station state machine.
* empty; examines LLC header to determine the destination of PDU, if DSAP
* is NULL then data unit destined for station else frame destined for SAP
* or connection; finds a matching open SAP, if one, forwards the packet
* to it; if no matching SAP, drops the packet. Returns 0 or the return of
* llc_conn_send_ev (that may well result in the connection being
* destroyed)
*/ */
int llc_pdu_router(struct llc_sap *sap, struct sock* sk, static void llc_station_rcv(struct sk_buff *skb)
struct sk_buff *skb, u8 type)
{ {
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_station *station = llc_station_get();
int rc = 0; struct llc_station_state_ev *ev = llc_station_ev(skb);
if (!pdu->dsap) { ev->type = LLC_STATION_EV_TYPE_PDU;
struct llc_station *station = llc_station_get(); ev->data.pdu.reason = 0;
struct llc_station_state_ev *ev = llc_station_ev(skb); llc_station_state_process(station, skb);
}
ev->type = LLC_STATION_EV_TYPE_PDU;
ev->data.pdu.reason = 0;
llc_station_send_ev(station, skb);
} else if (type == LLC_TYPE_1) {
struct llc_sap_state_ev *ev = llc_sap_ev(skb);
ev->type = LLC_SAP_EV_TYPE_PDU; /**
ev->data.pdu.reason = 0; * llc_conn_rcv - sends received pdus to the connection state machine
llc_sap_send_ev(sap, skb); * @sk: current connection structure.
} else if (type == LLC_TYPE_2) { * @skb: received frame.
struct llc_conn_state_ev *ev = llc_conn_ev(skb); *
struct llc_opt *llc = llc_sk(sk); * Sends received pdus to the connection state machine.
*/
int llc_conn_rcv(struct sock* sk, struct sk_buff *skb)
{
struct llc_conn_state_ev *ev = llc_conn_ev(skb);
struct llc_opt *llc = llc_sk(sk);
if (!llc->dev) if (!llc->dev)
llc->dev = skb->dev; llc->dev = skb->dev;
ev->type = LLC_CONN_EV_TYPE_PDU;
ev->data.pdu.reason = 0;
return llc_conn_state_process(sk, skb);
}
ev->type = LLC_CONN_EV_TYPE_PDU; /**
ev->data.pdu.reason = 0; * llc_sap_rcv - sends received pdus to the sap state machine
rc = llc_conn_send_ev(sk, skb); * @sap: current sap component structure.
} else * @skb: received frame.
rc = -EINVAL; *
return rc; * Sends received pdus to the sap state machine.
*/
static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb)
{
struct llc_sap_state_ev *ev = llc_sap_ev(skb);
ev->type = LLC_SAP_EV_TYPE_PDU;
ev->data.pdu.reason = 0;
llc_sap_state_process(sap, skb);
} }
/** /**
......
...@@ -52,6 +52,11 @@ static int llc_rtn_all_conns(struct llc_sap *sap); ...@@ -52,6 +52,11 @@ static int llc_rtn_all_conns(struct llc_sap *sap);
static struct llc_station llc_main_station; /* only one of its kind */ static struct llc_station llc_main_station; /* only one of its kind */
#undef LLC_REFCNT_DEBUG
#ifdef LLC_REFCNT_DEBUG
static atomic_t llc_sock_nr;
#endif
/** /**
* llc_sap_alloc - allocates and initializes sap. * llc_sap_alloc - allocates and initializes sap.
* *
...@@ -136,7 +141,7 @@ struct llc_sap *llc_sap_find(u8 sap_value) ...@@ -136,7 +141,7 @@ struct llc_sap *llc_sap_find(u8 sap_value)
* *
* This function processes frames that has received and timers that has * This function processes frames that has received and timers that has
* expired during sending an I pdu (refer to data_req_handler). frames * expired during sending an I pdu (refer to data_req_handler). frames
* queue by mac_indicate function (llc_mac.c) and timers queue by timer * queue by llc_rcv function (llc_mac.c) and timers queue by timer
* callback functions(llc_c_ac.c). * callback functions(llc_c_ac.c).
*/ */
static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb) static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
...@@ -146,13 +151,13 @@ static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -146,13 +151,13 @@ static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
if (llc_backlog_type(skb) == LLC_PACKET) { if (llc_backlog_type(skb) == LLC_PACKET) {
if (llc->state > 1) /* not closed */ if (llc->state > 1) /* not closed */
rc = llc_pdu_router(llc->sap, sk, skb, LLC_TYPE_2); rc = llc_conn_rcv(sk, skb);
else else
kfree_skb(skb); kfree_skb(skb);
} else if (llc_backlog_type(skb) == LLC_EVENT) { } else if (llc_backlog_type(skb) == LLC_EVENT) {
/* timer expiration event */ /* timer expiration event */
if (llc->state > 1) /* not closed */ if (llc->state > 1) /* not closed */
rc = llc_conn_send_ev(sk, skb); rc = llc_conn_state_process(sk, skb);
else else
llc_conn_free_ev(skb); llc_conn_free_ev(skb);
kfree_skb(skb); kfree_skb(skb);
...@@ -165,10 +170,12 @@ static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb) ...@@ -165,10 +170,12 @@ static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
} }
/** /**
* llc_sock_init - Initialize a socket with default llc values. * llc_sk_init - Initializes a socket with default llc values.
* @sk: socket to intiailize. * @sk: socket to intiailize.
*
* Initializes a socket with default llc values.
*/ */
int llc_sock_init(struct sock* sk) int llc_sk_init(struct sock* sk)
{ {
struct llc_opt *llc = kmalloc(sizeof(*llc), GFP_ATOMIC); struct llc_opt *llc = kmalloc(sizeof(*llc), GFP_ATOMIC);
int rc = -ENOMEM; int rc = -ENOMEM;
...@@ -198,61 +205,83 @@ int llc_sock_init(struct sock* sk) ...@@ -198,61 +205,83 @@ int llc_sock_init(struct sock* sk)
} }
/** /**
* __llc_sock_alloc - Allocates LLC sock * llc_sk_alloc - Allocates LLC sock
* @family: upper layer protocol family
* @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc)
* *
* Allocates a LLC sock and initializes it. Returns the new LLC sock * Allocates a LLC sock and initializes it. Returns the new LLC sock
* or %NULL if there's no memory available for one * or %NULL if there's no memory available for one
*/ */
struct sock *__llc_sock_alloc(void) struct sock *llc_sk_alloc(int family, int priority)
{ {
struct sock *sk = sk_alloc(PF_LLC, GFP_ATOMIC, 1, NULL); struct sock *sk = sk_alloc(family, priority, 1, NULL);
MOD_INC_USE_COUNT;
if (!sk) if (!sk)
goto out; goto decmod;
if (llc_sock_init(sk)) if (llc_sk_init(sk))
goto outsk; goto outsk;
sock_init_data(NULL, sk); sock_init_data(NULL, sk);
#ifdef LLC_REFCNT_DEBUG
atomic_inc(&llc_sock_nr);
printk(KERN_DEBUG "LLC socket %p created in %s, now we have %d alive\n", sk,
__FUNCTION__, atomic_read(&llc_sock_nr));
#endif
out: out:
return sk; return sk;
outsk: outsk:
sk_free(sk); sk_free(sk);
sk = NULL; sk = NULL;
decmod:
MOD_DEC_USE_COUNT;
goto out; goto out;
} }
/** /**
* __llc_sock_free - Frees a LLC socket * llc_sk_free - Frees a LLC socket
* @sk - socket to free * @sk - socket to free
* *
* Frees a LLC socket * Frees a LLC socket
*/ */
void __llc_sock_free(struct sock *sk, u8 free) void llc_sk_free(struct sock *sk)
{ {
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
llc->state = LLC_CONN_OUT_OF_SVC; llc->state = LLC_CONN_OUT_OF_SVC;
/* stop all (possibly) running timers */ /* Stop all (possibly) running timers */
llc_conn_ac_stop_all_timers(sk, NULL); llc_conn_ac_stop_all_timers(sk, NULL);
/* handle return of frames on lists */ #ifdef DEBUG_LLC_CONN_ALLOC
#if 0
printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __FUNCTION__, printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __FUNCTION__,
skb_queue_len(&llc->pdu_unack_q), skb_queue_len(&llc->pdu_unack_q),
skb_queue_len(&sk->write_queue)); skb_queue_len(&sk->write_queue));
#endif #endif
skb_queue_purge(&sk->receive_queue);
skb_queue_purge(&sk->write_queue); skb_queue_purge(&sk->write_queue);
skb_queue_purge(&llc->pdu_unack_q); skb_queue_purge(&llc->pdu_unack_q);
if (free) #ifdef LLC_REFCNT_DEBUG
sock_put(sk); if (atomic_read(&sk->refcnt) != 1) {
printk(KERN_DEBUG "Destruction of LLC sock %p delayed in %s, cnt=%d\n",
sk, __FUNCTION__, atomic_read(&sk->refcnt));
printk(KERN_DEBUG "%d LLC sockets are still alive\n",
atomic_read(&llc_sock_nr));
} else {
atomic_dec(&llc_sock_nr);
printk(KERN_DEBUG "LLC socket %p released in %s, %d are still alive\n", sk,
__FUNCTION__, atomic_read(&llc_sock_nr));
}
#endif
sock_put(sk);
MOD_DEC_USE_COUNT;
} }
/** /**
* llc_sock_reset - resets a connection * llc_sk_reset - resets a connection
* @sk: LLC socket to reset * @sk: LLC socket to reset
* *
* Resets a connection to the out of service state. Stops its timers * Resets a connection to the out of service state. Stops its timers
* and frees any frames in the queues of the connection. * and frees any frames in the queues of the connection.
*/ */
void llc_sock_reset(struct sock *sk) void llc_sk_reset(struct sock *sk)
{ {
struct llc_opt *llc = llc_sk(sk); struct llc_opt *llc = llc_sk(sk);
...@@ -286,8 +315,6 @@ void llc_sock_reset(struct sock *sk) ...@@ -286,8 +315,6 @@ void llc_sock_reset(struct sock *sk)
static int llc_rtn_all_conns(struct llc_sap *sap) static int llc_rtn_all_conns(struct llc_sap *sap)
{ {
int rc = 0; int rc = 0;
union llc_u_prim_data prim_data;
struct llc_prim_if_block prim;
struct list_head *entry, *tmp; struct list_head *entry, *tmp;
spin_lock_bh(&sap->sk_list.lock); spin_lock_bh(&sap->sk_list.lock);
...@@ -296,12 +323,8 @@ static int llc_rtn_all_conns(struct llc_sap *sap) ...@@ -296,12 +323,8 @@ static int llc_rtn_all_conns(struct llc_sap *sap)
list_for_each_safe(entry, tmp, &sap->sk_list.list) { list_for_each_safe(entry, tmp, &sap->sk_list.list) {
struct llc_opt *llc = list_entry(entry, struct llc_opt, node); struct llc_opt *llc = list_entry(entry, struct llc_opt, node);
prim.sap = sap;
prim_data.disc.sk = llc->sk;
prim.prim = LLC_DISC_PRIM;
prim.data = &prim_data;
llc->state = LLC_CONN_STATE_TEMP; llc->state = LLC_CONN_STATE_TEMP;
if (sap->req(&prim)) if (llc_send_disc(llc->sk))
rc = 1; rc = 1;
} }
out: out:
...@@ -320,14 +343,14 @@ struct llc_station *llc_station_get(void) ...@@ -320,14 +343,14 @@ struct llc_station *llc_station_get(void)
} }
/** /**
* llc_station_send_ev: queue event and try to process queue. * llc_station_state_process: queue event and try to process queue.
* @station: Address of the station * @station: Address of the station
* @skb: Address of the event * @skb: Address of the event
* *
* Queues an event (on the station event queue) for handling by the * Queues an event (on the station event queue) for handling by the
* station state machine and attempts to process any queued-up events. * station state machine and attempts to process any queued-up events.
*/ */
void llc_station_send_ev(struct llc_station *station, struct sk_buff *skb) void llc_station_state_process(struct llc_station *station, struct sk_buff *skb)
{ {
spin_lock_bh(&station->ev_q.lock); spin_lock_bh(&station->ev_q.lock);
skb_queue_tail(&station->ev_q.list, skb); skb_queue_tail(&station->ev_q.list, skb);
...@@ -557,13 +580,13 @@ static int llc_proc_get_info(char *bf, char **start, off_t offset, int length) ...@@ -557,13 +580,13 @@ static int llc_proc_get_info(char *bf, char **start, off_t offset, int length)
static struct packet_type llc_packet_type = { static struct packet_type llc_packet_type = {
.type = __constant_htons(ETH_P_802_2), .type = __constant_htons(ETH_P_802_2),
.func = mac_indicate, .func = llc_rcv,
.data = (void *)1, .data = (void *)1,
}; };
static struct packet_type llc_tr_packet_type = { static struct packet_type llc_tr_packet_type = {
.type = __constant_htons(ETH_P_TR_802_2), .type = __constant_htons(ETH_P_TR_802_2),
.func = mac_indicate, .func = llc_rcv,
.data = (void *)1, .data = (void *)1,
}; };
...@@ -585,7 +608,7 @@ static int __init llc_init(void) ...@@ -585,7 +608,7 @@ static int __init llc_init(void)
skb_queue_head_init(&llc_main_station.mac_pdu_q); skb_queue_head_init(&llc_main_station.mac_pdu_q);
skb_queue_head_init(&llc_main_station.ev_q.list); skb_queue_head_init(&llc_main_station.ev_q.list);
spin_lock_init(&llc_main_station.ev_q.lock); spin_lock_init(&llc_main_station.ev_q.lock);
skb = alloc_skb(1, GFP_ATOMIC); skb = alloc_skb(0, GFP_ATOMIC);
if (!skb) if (!skb)
goto err; goto err;
llc_build_offset_table(); llc_build_offset_table();
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
#include <net/llc_mac.h> #include <net/llc_mac.h>
#include <net/llc_main.h> #include <net/llc_main.h>
static int 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 __inline__ int llc_get_hdr_len(u8 pdu_type); static __inline__ int llc_get_hdr_len(u8 pdu_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);
...@@ -60,9 +60,7 @@ void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value) ...@@ -60,9 +60,7 @@ void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value)
u8 pdu_type; u8 pdu_type;
struct llc_pdu_sn *pdu; struct llc_pdu_sn *pdu;
if (llc_pdu_decode_pdu_type(skb, &pdu_type)) llc_pdu_decode_pdu_type(skb, &pdu_type);
goto out;
pdu = llc_pdu_sn_hdr(skb); pdu = llc_pdu_sn_hdr(skb);
switch (pdu_type) { switch (pdu_type) {
...@@ -74,7 +72,6 @@ void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value) ...@@ -74,7 +72,6 @@ void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value)
pdu->ctrl_1 |= (pdu->ctrl_1 & 0xEF) | (bit_value << 4); pdu->ctrl_1 |= (pdu->ctrl_1 & 0xEF) | (bit_value << 4);
break; break;
} }
out:;
} }
/** /**
...@@ -86,15 +83,12 @@ out:; ...@@ -86,15 +83,12 @@ out:;
* PDU). In I or S pdus, p/f bit is right bit of fourth byte in header. In * PDU). In I or S pdus, p/f bit is right bit of fourth byte in header. In
* U pdus p/f bit is fifth bit of third byte. * U pdus p/f bit is fifth bit of third byte.
*/ */
int llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit) void llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit)
{ {
u8 pdu_type; u8 pdu_type;
struct llc_pdu_sn *pdu; struct llc_pdu_sn *pdu;
int rc = llc_pdu_decode_pdu_type(skb, &pdu_type);
if (rc)
goto out;
llc_pdu_decode_pdu_type(skb, &pdu_type);
pdu = llc_pdu_sn_hdr(skb); pdu = llc_pdu_sn_hdr(skb);
switch (pdu_type) { switch (pdu_type) {
...@@ -106,22 +100,19 @@ int llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit) ...@@ -106,22 +100,19 @@ int llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit)
*pf_bit = (pdu->ctrl_1 & LLC_U_PF_BIT_MASK) >> 4; *pf_bit = (pdu->ctrl_1 & LLC_U_PF_BIT_MASK) >> 4;
break; break;
} }
out:
return 0;
} }
/** /**
* llc_pdu_decode_cr_bit - extracs command response bit from LLC header * llc_pdu_decode_cr_bit - extracts command response bit from LLC header
* @skb: input skb that c/r bit must be extracted from it. * @skb: input skb that c/r bit must be extracted from it.
* @cr_bit: command/response bit (0 or 1). * @cr_bit: command/response bit (0 or 1).
* *
* This function extracts command/response bit from LLC header. this bit * This function extracts command/response bit from LLC header. this bit
* is right bit of source SAP. * is right bit of source SAP.
*/ */
int llc_pdu_decode_cr_bit(struct sk_buff *skb, u8 *cr_bit) void llc_pdu_decode_cr_bit(struct sk_buff *skb, u8 *cr_bit)
{ {
*cr_bit = llc_pdu_un_hdr(skb)->ssap & LLC_PDU_CMD_RSP_MASK; *cr_bit = llc_pdu_un_hdr(skb)->ssap & LLC_PDU_CMD_RSP_MASK;
return 0;
} }
/** /**
...@@ -131,13 +122,12 @@ int llc_pdu_decode_cr_bit(struct sk_buff *skb, u8 *cr_bit) ...@@ -131,13 +122,12 @@ int llc_pdu_decode_cr_bit(struct sk_buff *skb, u8 *cr_bit)
* *
* This function extracts source address(MAC) of input frame. * This function extracts source address(MAC) of input frame.
*/ */
int llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa) void llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa)
{ {
if (skb->protocol == ntohs(ETH_P_802_2)) if (skb->protocol == ntohs(ETH_P_802_2))
memcpy(sa, ((struct ethhdr *)skb->mac.raw)->h_source, ETH_ALEN); memcpy(sa, ((struct ethhdr *)skb->mac.raw)->h_source, ETH_ALEN);
else if (skb->protocol == ntohs(ETH_P_TR_802_2)) else if (skb->protocol == ntohs(ETH_P_TR_802_2))
memcpy(sa, ((struct trh_hdr *)skb->mac.raw)->saddr, ETH_ALEN); memcpy(sa, ((struct trh_hdr *)skb->mac.raw)->saddr, ETH_ALEN);
return 0;
} }
/** /**
...@@ -147,13 +137,12 @@ int llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa) ...@@ -147,13 +137,12 @@ int llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa)
* *
* This function extracts destination address(MAC) of input frame. * This function extracts destination address(MAC) of input frame.
*/ */
int llc_pdu_decode_da(struct sk_buff *skb, u8 *da) void llc_pdu_decode_da(struct sk_buff *skb, u8 *da)
{ {
if (skb->protocol == ntohs(ETH_P_802_2)) if (skb->protocol == ntohs(ETH_P_802_2))
memcpy(da, ((struct ethhdr *)skb->mac.raw)->h_dest, ETH_ALEN); memcpy(da, ((struct ethhdr *)skb->mac.raw)->h_dest, ETH_ALEN);
else if (skb->protocol == ntohs(ETH_P_TR_802_2)) else if (skb->protocol == ntohs(ETH_P_TR_802_2))
memcpy(da, ((struct trh_hdr *)skb->mac.raw)->daddr, ETH_ALEN); memcpy(da, ((struct trh_hdr *)skb->mac.raw)->daddr, ETH_ALEN);
return 0;
} }
/** /**
...@@ -164,10 +153,9 @@ int llc_pdu_decode_da(struct sk_buff *skb, u8 *da) ...@@ -164,10 +153,9 @@ int llc_pdu_decode_da(struct sk_buff *skb, u8 *da)
* This function extracts destination SAP of input frame. right bit of * This function extracts destination SAP of input frame. right bit of
* DSAP designates individual/group SAP. * DSAP designates individual/group SAP.
*/ */
int llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap) void llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap)
{ {
*dsap = llc_pdu_un_hdr(skb)->dsap & 0xFE; *dsap = llc_pdu_un_hdr(skb)->dsap & 0xFE;
return 0;
} }
/** /**
...@@ -175,13 +163,12 @@ int llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap) ...@@ -175,13 +163,12 @@ int llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap)
* @skb: input skb that source SAP must be extracted from it. * @skb: input skb that source SAP must be extracted from it.
* @ssap: source SAP (output argument). * @ssap: source SAP (output argument).
* *
* This function extracts source SAP of input frame. right bit of SSAP is * This function extracts source SAP of input frame. Right bit of SSAP is
* command/response bit. * command/response bit.
*/ */
int llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap) void llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap)
{ {
*ssap = llc_pdu_un_hdr(skb)->ssap & 0xFE; *ssap = llc_pdu_un_hdr(skb)->ssap & 0xFE;
return 0;
} }
/** /**
...@@ -190,13 +177,12 @@ int llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap) ...@@ -190,13 +177,12 @@ int llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap)
* *
* This function sets third byte of LLC header as a UI PDU. * This function sets third byte of LLC header as a UI PDU.
*/ */
int llc_pdu_init_as_ui_cmd(struct sk_buff *skb) void llc_pdu_init_as_ui_cmd(struct sk_buff *skb)
{ {
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
pdu->ctrl_1 = LLC_PDU_TYPE_U; pdu->ctrl_1 = LLC_PDU_TYPE_U;
pdu->ctrl_1 |= LLC_1_PDU_CMD_UI; pdu->ctrl_1 |= LLC_1_PDU_CMD_UI;
return 0;
} }
/** /**
...@@ -206,8 +192,8 @@ int llc_pdu_init_as_ui_cmd(struct sk_buff *skb) ...@@ -206,8 +192,8 @@ int llc_pdu_init_as_ui_cmd(struct sk_buff *skb)
* This function sets third,fourth,fifth and sixth bytes of LLC header as * This function sets third,fourth,fifth and sixth bytes of LLC header as
* a XID PDU. * a XID PDU.
*/ */
int llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported, void llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported,
u8 rx_window) u8 rx_window)
{ {
struct llc_xid_info *xid_info; struct llc_xid_info *xid_info;
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
...@@ -220,7 +206,6 @@ int llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported, ...@@ -220,7 +206,6 @@ int llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported,
xid_info->type = svcs_supported; xid_info->type = svcs_supported;
xid_info->rw = rx_window << 1; /* size of recieve window */ xid_info->rw = rx_window << 1; /* size of recieve window */
skb_put(skb, 3); skb_put(skb, 3);
return 0;
} }
/** /**
...@@ -229,14 +214,13 @@ int llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported, ...@@ -229,14 +214,13 @@ int llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported,
* *
* Sets a PDU as TEST * Sets a PDU as TEST
*/ */
int llc_pdu_init_as_test_cmd(struct sk_buff *skb) void llc_pdu_init_as_test_cmd(struct sk_buff *skb)
{ {
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
pdu->ctrl_1 = LLC_PDU_TYPE_U; pdu->ctrl_1 = LLC_PDU_TYPE_U;
pdu->ctrl_1 |= LLC_1_PDU_CMD_TEST; pdu->ctrl_1 |= LLC_1_PDU_CMD_TEST;
pdu->ctrl_1 |= LLC_U_PF_BIT_MASK; pdu->ctrl_1 |= LLC_U_PF_BIT_MASK;
return 0;
} }
/** /**
...@@ -246,18 +230,17 @@ int llc_pdu_init_as_test_cmd(struct sk_buff *skb) ...@@ -246,18 +230,17 @@ int llc_pdu_init_as_test_cmd(struct sk_buff *skb)
* *
* Builds a pdu frame as a DISC command. * Builds a pdu frame as a DISC command.
*/ */
int llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit) void llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit)
{ {
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
pdu->ctrl_1 = LLC_PDU_TYPE_U; pdu->ctrl_1 = LLC_PDU_TYPE_U;
pdu->ctrl_1 |= LLC_2_PDU_CMD_DISC; pdu->ctrl_1 |= LLC_2_PDU_CMD_DISC;
pdu->ctrl_1 |= ((p_bit & 1) << 4) & LLC_U_PF_BIT_MASK; pdu->ctrl_1 |= ((p_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
return 0;
} }
/** /**
* pdu_init_as_i_cmd - builds I pdu * llc_pdu_init_as_i_cmd - builds I pdu
* @skb: Address of the skb to build * @skb: Address of the skb to build
* @p_bit: The P bit to set in the PDU * @p_bit: The P bit to set in the PDU
* @ns: The sequence number of the data PDU * @ns: The sequence number of the data PDU
...@@ -265,7 +248,7 @@ int llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit) ...@@ -265,7 +248,7 @@ int llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit)
* *
* Builds a pdu frame as an I command. * Builds a pdu frame as an I command.
*/ */
int llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr) void llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr)
{ {
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
...@@ -274,18 +257,17 @@ int llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr) ...@@ -274,18 +257,17 @@ int llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr)
pdu->ctrl_2 |= (p_bit & LLC_I_PF_BIT_MASK); /* p/f bit */ pdu->ctrl_2 |= (p_bit & LLC_I_PF_BIT_MASK); /* p/f bit */
pdu->ctrl_1 |= (ns << 1) & 0xFE; /* set N(S) in bits 2..8 */ pdu->ctrl_1 |= (ns << 1) & 0xFE; /* set N(S) in bits 2..8 */
pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */
return 0;
} }
/** /**
* pdu_init_as_rej_cmd - builds REJ PDU * llc_pdu_init_as_rej_cmd - builds REJ PDU
* @skb: Address of the skb to build * @skb: Address of the skb to build
* @p_bit: The P bit to set in the PDU * @p_bit: The P bit to set in the PDU
* @nr: The seq. number of the expected I PDU from the remote * @nr: The seq. number of the expected I PDU from the remote
* *
* Builds a pdu frame as a REJ command. * Builds a pdu frame as a REJ command.
*/ */
int llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) void llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
{ {
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
...@@ -295,18 +277,17 @@ int llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) ...@@ -295,18 +277,17 @@ int llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
pdu->ctrl_2 |= p_bit & LLC_S_PF_BIT_MASK; pdu->ctrl_2 |= p_bit & LLC_S_PF_BIT_MASK;
pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */ pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */
pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */
return 0;
} }
/** /**
* pdu_init_as_rnr_cmd - builds RNR pdu * llc_pdu_init_as_rnr_cmd - builds RNR pdu
* @skb: Address of the skb to build * @skb: Address of the skb to build
* @p_bit: The P bit to set in the PDU * @p_bit: The P bit to set in the PDU
* @nr: The seq. number of the expected I PDU from the remote * @nr: The seq. number of the expected I PDU from the remote
* *
* Builds a pdu frame as an RNR command. * Builds a pdu frame as an RNR command.
*/ */
int llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) void llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
{ {
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
...@@ -316,18 +297,17 @@ int llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) ...@@ -316,18 +297,17 @@ int llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
pdu->ctrl_2 |= p_bit & LLC_S_PF_BIT_MASK; pdu->ctrl_2 |= p_bit & LLC_S_PF_BIT_MASK;
pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */ pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */
pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */
return 0;
} }
/** /**
* pdu_init_as_rr_cmd - Builds RR pdu * llc_pdu_init_as_rr_cmd - Builds RR pdu
* @skb: Address of the skb to build * @skb: Address of the skb to build
* @p_bit: The P bit to set in the PDU * @p_bit: The P bit to set in the PDU
* @nr: The seq. number of the expected I PDU from the remote * @nr: The seq. number of the expected I PDU from the remote
* *
* Builds a pdu frame as an RR command. * Builds a pdu frame as an RR command.
*/ */
int llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) void llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
{ {
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
...@@ -336,53 +316,50 @@ int llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) ...@@ -336,53 +316,50 @@ int llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
pdu->ctrl_2 = p_bit & LLC_S_PF_BIT_MASK; pdu->ctrl_2 = p_bit & LLC_S_PF_BIT_MASK;
pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */ pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */
pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */
return 0;
} }
/** /**
* pdu_init_as_sabme_cmd - builds SABME pdu * llc_pdu_init_as_sabme_cmd - builds SABME pdu
* @skb: Address of the skb to build * @skb: Address of the skb to build
* @p_bit: The P bit to set in the PDU * @p_bit: The P bit to set in the PDU
* *
* Builds a pdu frame as an SABME command. * Builds a pdu frame as an SABME command.
*/ */
int llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit) void llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit)
{ {
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
pdu->ctrl_1 = LLC_PDU_TYPE_U; pdu->ctrl_1 = LLC_PDU_TYPE_U;
pdu->ctrl_1 |= LLC_2_PDU_CMD_SABME; pdu->ctrl_1 |= LLC_2_PDU_CMD_SABME;
pdu->ctrl_1 |= ((p_bit & 1) << 4) & LLC_U_PF_BIT_MASK; pdu->ctrl_1 |= ((p_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
return 0;
} }
/** /**
* pdu_init_as_dm_rsp - builds DM response pdu * llc_pdu_init_as_dm_rsp - builds DM response pdu
* @skb: Address of the skb to build * @skb: Address of the skb to build
* @f_bit: The F bit to set in the PDU * @f_bit: The F bit to set in the PDU
* *
* Builds a pdu frame as a DM response. * Builds a pdu frame as a DM response.
*/ */
int llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit) void llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit)
{ {
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
pdu->ctrl_1 = LLC_PDU_TYPE_U; pdu->ctrl_1 = LLC_PDU_TYPE_U;
pdu->ctrl_1 |= LLC_2_PDU_RSP_DM; pdu->ctrl_1 |= LLC_2_PDU_RSP_DM;
pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK; pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
return 0;
} }
/** /**
* pdu_init_as_xid_rsp - builds XID response PDU * llc_pdu_init_as_xid_rsp - builds XID response PDU
* @skb: Address of the skb to build * @skb: Address of the skb to build
* @svcs_supported: The class of the LLC (I or II) * @svcs_supported: The class of the LLC (I or II)
* @rx_window: The size of the receive window of the LLC * @rx_window: The size of the receive window of the LLC
* *
* Builds a pdu frame as an XID response. * Builds a pdu frame as an XID response.
*/ */
int llc_pdu_init_as_xid_rsp(struct sk_buff *skb, u8 svcs_supported, void llc_pdu_init_as_xid_rsp(struct sk_buff *skb, u8 svcs_supported,
u8 rx_window) u8 rx_window)
{ {
struct llc_xid_info *xid_info; struct llc_xid_info *xid_info;
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
...@@ -396,17 +373,16 @@ int llc_pdu_init_as_xid_rsp(struct sk_buff *skb, u8 svcs_supported, ...@@ -396,17 +373,16 @@ int llc_pdu_init_as_xid_rsp(struct sk_buff *skb, u8 svcs_supported,
xid_info->type = svcs_supported; xid_info->type = svcs_supported;
xid_info->rw = rx_window << 1; xid_info->rw = rx_window << 1;
skb_put(skb, 3); skb_put(skb, 3);
return 0;
} }
/** /**
* pdu_init_as_test_rsp - build TEST response PDU * llc_pdu_init_as_test_rsp - build TEST response PDU
* @skb: Address of the skb to build * @skb: Address of the skb to build
* @ev_skb: The received TEST command PDU frame * @ev_skb: The received TEST command PDU frame
* *
* Builds a pdu frame as a TEST response. * Builds a pdu frame as a TEST response.
*/ */
int llc_pdu_init_as_test_rsp(struct sk_buff *skb, struct sk_buff *ev_skb) void llc_pdu_init_as_test_rsp(struct sk_buff *skb, struct sk_buff *ev_skb)
{ {
int dsize; int dsize;
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
...@@ -421,12 +397,11 @@ int llc_pdu_init_as_test_rsp(struct sk_buff *skb, struct sk_buff *ev_skb) ...@@ -421,12 +397,11 @@ int llc_pdu_init_as_test_rsp(struct sk_buff *skb, struct sk_buff *ev_skb)
memcpy(((u8 *)pdu) + 3, ((u8 *)ev_pdu) + 3, dsize); memcpy(((u8 *)pdu) + 3, ((u8 *)ev_pdu) + 3, dsize);
skb_put(skb, dsize); skb_put(skb, dsize);
} }
return 0;
} }
/** /**
* pdu_init_as_frmr_rsp - builds FRMR response PDU * llc_pdu_init_as_frmr_rsp - builds FRMR response PDU
* @pdu_frame: Address of the frame to build * @skb: Address of the frame to build
* @prev_pdu: The rejected PDU frame * @prev_pdu: The rejected PDU frame
* @f_bit: The F bit to set in the PDU * @f_bit: The F bit to set in the PDU
* @vs: tx state vari value for the data link conn at the rejecting LLC * @vs: tx state vari value for the data link conn at the rejecting LLC
...@@ -435,8 +410,8 @@ int llc_pdu_init_as_test_rsp(struct sk_buff *skb, struct sk_buff *ev_skb) ...@@ -435,8 +410,8 @@ int llc_pdu_init_as_test_rsp(struct sk_buff *skb, struct sk_buff *ev_skb)
* *
* Builds a pdu frame as a FRMR response. * Builds a pdu frame as a FRMR response.
*/ */
int llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, struct llc_pdu_sn *prev_pdu, void llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, struct llc_pdu_sn *prev_pdu,
u8 f_bit, u8 vs, u8 vr, u8 vzyxw) u8 f_bit, u8 vs, u8 vr, u8 vzyxw)
{ {
struct llc_frmr_info *frmr_info; struct llc_frmr_info *frmr_info;
u8 prev_pf = 0; u8 prev_pf = 0;
...@@ -460,18 +435,17 @@ int llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, struct llc_pdu_sn *prev_pdu, ...@@ -460,18 +435,17 @@ int llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, struct llc_pdu_sn *prev_pdu,
FRMR_INFO_SET_PDU_INVALID_Nr_IND(frmr_info, vzyxw); FRMR_INFO_SET_PDU_INVALID_Nr_IND(frmr_info, vzyxw);
FRMR_INFO_SET_PDU_INVALID_Ns_IND(frmr_info, vzyxw); FRMR_INFO_SET_PDU_INVALID_Ns_IND(frmr_info, vzyxw);
skb_put(skb, 5); skb_put(skb, 5);
return 0;
} }
/** /**
* pdu_init_as_rr_rsp - builds RR response pdu * llc_pdu_init_as_rr_rsp - builds RR response pdu
* @skb: Address of the skb to build * @skb: Address of the skb to build
* @f_bit: The F bit to set in the PDU * @f_bit: The F bit to set in the PDU
* @nr: The seq. number of the expected data PDU from the remote * @nr: The seq. number of the expected data PDU from the remote
* *
* Builds a pdu frame as an RR response. * Builds a pdu frame as an RR response.
*/ */
int llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) void llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
{ {
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
...@@ -481,18 +455,17 @@ int llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) ...@@ -481,18 +455,17 @@ int llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK; pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK;
pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */ pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */
pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */
return 0;
} }
/** /**
* pdu_init_as_rej_rsp - builds REJ response pdu * llc_pdu_init_as_rej_rsp - builds REJ response pdu
* @skb: Address of the skb to build * @skb: Address of the skb to build
* @f_bit: The F bit to set in the PDU * @f_bit: The F bit to set in the PDU
* @nr: The seq. number of the expected data PDU from the remote * @nr: The seq. number of the expected data PDU from the remote
* *
* Builds a pdu frame as a REJ response. * Builds a pdu frame as a REJ response.
*/ */
int llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) void llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
{ {
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
...@@ -502,18 +475,17 @@ int llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) ...@@ -502,18 +475,17 @@ int llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK; pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK;
pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */ pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */
pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */
return 0;
} }
/** /**
* pdu_init_as_rnr_rsp - builds RNR response pdu * llc_pdu_init_as_rnr_rsp - builds RNR response pdu
* @pdu_frame: Address of the frame to build * @skb: Address of the frame to build
* @f_bit: The F bit to set in the PDU * @f_bit: The F bit to set in the PDU
* @nr: The seq. number of the expected data PDU from the remote * @nr: The seq. number of the expected data PDU from the remote
* *
* Builds a pdu frame as an RNR response. * Builds a pdu frame as an RNR response.
*/ */
int llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) void llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
{ {
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
...@@ -523,24 +495,22 @@ int llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) ...@@ -523,24 +495,22 @@ int llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr)
pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK; pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK;
pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */ pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */
pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */
return 0;
} }
/** /**
* pdu_init_as_ua_rsp - builds UA response pdu * llc_pdu_init_as_ua_rsp - builds UA response pdu
* @skb: Address of the frame to build * @skb: Address of the frame to build
* @f_bit: The F bit to set in the PDU * @f_bit: The F bit to set in the PDU
* *
* Builds a pdu frame as a UA response. * Builds a pdu frame as a UA response.
*/ */
int llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit) void llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit)
{ {
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
pdu->ctrl_1 = LLC_PDU_TYPE_U; pdu->ctrl_1 = LLC_PDU_TYPE_U;
pdu->ctrl_1 |= LLC_2_PDU_RSP_UA; pdu->ctrl_1 |= LLC_2_PDU_RSP_UA;
pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK; pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK;
return 0;
} }
/** /**
...@@ -548,9 +518,9 @@ int llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit) ...@@ -548,9 +518,9 @@ int llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit)
* @skb: input skb that type of it must be designated. * @skb: input skb that type of it must be designated.
* @type: type of PDU (output argument). * @type: type of PDU (output argument).
* *
* This function designates type of PDU (I,S or U). * This function designates type of PDU (I, S or U).
*/ */
static int llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type) static void llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type)
{ {
struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
...@@ -561,7 +531,6 @@ static int llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type) ...@@ -561,7 +531,6 @@ static int llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type)
*type = LLC_PDU_TYPE_S; *type = LLC_PDU_TYPE_S;
} else } else
*type = LLC_PDU_TYPE_I; *type = LLC_PDU_TYPE_I;
return 0;
} }
/** /**
...@@ -571,7 +540,7 @@ static int llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type) ...@@ -571,7 +540,7 @@ static int llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type)
* *
* This function designates which component of LLC must handle this PDU. * This function designates which component of LLC must handle this PDU.
*/ */
int llc_decode_pdu_type(struct sk_buff *skb, u8 *dest) void llc_decode_pdu_type(struct sk_buff *skb, u8 *dest)
{ {
u8 type = LLC_DEST_CONN; /* I-PDU or S-PDU type */ u8 type = LLC_DEST_CONN; /* I-PDU or S-PDU type */
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
...@@ -596,7 +565,6 @@ int llc_decode_pdu_type(struct sk_buff *skb, u8 *dest) ...@@ -596,7 +565,6 @@ int llc_decode_pdu_type(struct sk_buff *skb, u8 *dest)
} }
out: out:
*dest = type; *dest = type;
return 0;
} }
/** /**
......
...@@ -57,13 +57,10 @@ int llc_sap_action_send_ui(struct llc_sap *sap, struct sk_buff *skb) ...@@ -57,13 +57,10 @@ int llc_sap_action_send_ui(struct llc_sap *sap, struct sk_buff *skb)
llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap, llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap,
prim_data->daddr.lsap, LLC_PDU_CMD); prim_data->daddr.lsap, LLC_PDU_CMD);
rc = llc_pdu_init_as_ui_cmd(skb); llc_pdu_init_as_ui_cmd(skb);
if (rc)
goto out;
rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac); rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac);
if (!rc) if (!rc)
llc_sap_send_pdu(sap, skb); llc_sap_send_pdu(sap, skb);
out:
return rc; return rc;
} }
...@@ -85,13 +82,10 @@ int llc_sap_action_send_xid_c(struct llc_sap *sap, struct sk_buff *skb) ...@@ -85,13 +82,10 @@ int llc_sap_action_send_xid_c(struct llc_sap *sap, struct sk_buff *skb)
llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap, llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap,
prim_data->daddr.lsap, LLC_PDU_CMD); prim_data->daddr.lsap, LLC_PDU_CMD);
rc = 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);
if (rc)
goto out;
rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac); rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac);
if (!rc) if (!rc)
llc_sap_send_pdu(sap, skb); llc_sap_send_pdu(sap, skb);
out:
return rc; return rc;
} }
...@@ -118,9 +112,7 @@ int llc_sap_action_send_xid_r(struct llc_sap *sap, struct sk_buff *skb) ...@@ -118,9 +112,7 @@ int llc_sap_action_send_xid_r(struct llc_sap *sap, struct sk_buff *skb)
nskb->dev = skb->dev; nskb->dev = skb->dev;
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);
rc = 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);
if (rc)
goto out;
rc = lan_hdrs_init(nskb, mac_sa, mac_da); rc = lan_hdrs_init(nskb, mac_sa, mac_da);
if (!rc) if (!rc)
llc_sap_send_pdu(sap, nskb); llc_sap_send_pdu(sap, nskb);
...@@ -146,13 +138,10 @@ int llc_sap_action_send_test_c(struct llc_sap *sap, struct sk_buff *skb) ...@@ -146,13 +138,10 @@ int llc_sap_action_send_test_c(struct llc_sap *sap, struct sk_buff *skb)
llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap, llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap,
prim_data->daddr.lsap, LLC_PDU_CMD); prim_data->daddr.lsap, LLC_PDU_CMD);
rc = llc_pdu_init_as_test_cmd(skb); llc_pdu_init_as_test_cmd(skb);
if (rc)
goto out;
rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac); rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac);
if (!rc) if (!rc)
llc_sap_send_pdu(sap, skb); llc_sap_send_pdu(sap, skb);
out:
return rc; return rc;
} }
...@@ -171,9 +160,7 @@ int llc_sap_action_send_test_r(struct llc_sap *sap, struct sk_buff *skb) ...@@ -171,9 +160,7 @@ int llc_sap_action_send_test_r(struct llc_sap *sap, struct sk_buff *skb)
nskb->dev = skb->dev; nskb->dev = skb->dev;
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);
rc = llc_pdu_init_as_test_rsp(nskb, skb); llc_pdu_init_as_test_rsp(nskb, skb);
if (rc)
goto out;
rc = lan_hdrs_init(nskb, mac_sa, mac_da); rc = lan_hdrs_init(nskb, mac_sa, mac_da);
if (!rc) if (!rc)
llc_sap_send_pdu(sap, nskb); llc_sap_send_pdu(sap, nskb);
......
...@@ -23,7 +23,6 @@ ...@@ -23,7 +23,6 @@
#include <net/llc_pdu.h> #include <net/llc_pdu.h>
#include <linux/if_tr.h> #include <linux/if_tr.h>
static void llc_sap_free_ev(struct llc_sap *sap, struct sk_buff *skb);
static int llc_sap_next_state(struct llc_sap *sap, struct sk_buff *skb); static int llc_sap_next_state(struct llc_sap *sap, struct sk_buff *skb);
static int llc_exec_sap_trans_actions(struct llc_sap *sap, static int llc_exec_sap_trans_actions(struct llc_sap *sap,
struct llc_sap_state_trans *trans, struct llc_sap_state_trans *trans,
...@@ -52,8 +51,7 @@ void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk) ...@@ -52,8 +51,7 @@ void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk)
* @sap: SAP * @sap: SAP
* @sk: pointer to connection * @sk: pointer to connection
* *
* This function removes a connection from connection_list of a SAP. * This function removes a connection from sk_list.list of a SAP.
* List locking is performed by caller (rtn_all_conns).
*/ */
void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk) void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk)
{ {
...@@ -64,23 +62,25 @@ void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk) ...@@ -64,23 +62,25 @@ void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk)
} }
/** /**
* llc_sap_send_ev - sends event to SAP state machine * llc_sap_state_process - sends event to SAP state machine
* @sap: pointer to SAP * @sap: pointer to SAP
* @skb: pointer to occurred event * @skb: pointer to occurred event
* *
* After executing actions of the event, upper layer will be indicated * After executing actions of the event, upper layer will be indicated
* if needed(on receiving an UI frame). * if needed(on receiving an UI frame).
*/ */
void llc_sap_send_ev(struct llc_sap *sap, struct sk_buff *skb) void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb)
{ {
struct llc_sap_state_ev *ev = llc_sap_ev(skb); struct llc_sap_state_ev *ev = llc_sap_ev(skb);
llc_sap_next_state(sap, skb); llc_sap_next_state(sap, skb);
if (ev->ind_cfm_flag == LLC_IND) { if (ev->ind_cfm_flag == LLC_IND)
skb_get(skb);
sap->ind(ev->prim); sap->ind(ev->prim);
} else if (ev->type == LLC_SAP_EV_TYPE_PDU)
llc_sap_free_ev(sap, skb); kfree_skb(skb);
else
printk(KERN_INFO ":%s !kfree_skb & it is %s in a list\n",
__FUNCTION__, skb->list ? "" : "NOT");
} }
/** /**
...@@ -142,19 +142,6 @@ void llc_sap_send_pdu(struct llc_sap *sap, struct sk_buff *skb) ...@@ -142,19 +142,6 @@ void llc_sap_send_pdu(struct llc_sap *sap, struct sk_buff *skb)
kfree_skb(skb); kfree_skb(skb);
} }
/**
* llc_sap_free_ev - frees an sap event
* @sap: pointer to SAP
* @skb: released event
*/
static void llc_sap_free_ev(struct llc_sap *sap, struct sk_buff *skb)
{
struct llc_sap_state_ev *ev = llc_sap_ev(skb);
if (ev->type == LLC_SAP_EV_TYPE_PDU)
kfree_skb(skb);
}
/** /**
* llc_sap_next_state - finds transition, execs actions & change SAP state * llc_sap_next_state - finds transition, execs actions & change SAP state
* @sap: pointer to SAP * @sap: pointer to SAP
...@@ -206,7 +193,7 @@ static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap, ...@@ -206,7 +193,7 @@ static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap,
/* search thru events for this state until list exhausted or until /* search thru events for this state until list exhausted or until
* its obvious the event is not valid for the current state * its obvious the event is not valid for the current state
*/ */
for (next_trans = curr_state->transitions; next_trans [i]->ev; i++) for (next_trans = curr_state->transitions; next_trans[i]->ev; i++)
if (!next_trans[i]->ev(sap, skb)) { if (!next_trans[i]->ev(sap, skb)) {
/* got event match; return it */ /* got event match; return it */
rc = next_trans[i]; rc = next_trans[i];
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
* connections. * connections.
* *
* Copyright (c) 2001 by Jay Schulist <jschlst@samba.org> * Copyright (c) 2001 by Jay Schulist <jschlst@samba.org>
* 2002 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.
...@@ -38,6 +39,7 @@ ...@@ -38,6 +39,7 @@
#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 <linux/llc.h> #include <linux/llc.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
...@@ -46,7 +48,6 @@ ...@@ -46,7 +48,6 @@
/* 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;
static u16 llc_ui_sap_link_no_max[256]; static u16 llc_ui_sap_link_no_max[256];
static u8 llc_ui_addrany[IFHWADDRLEN];
static struct sockaddr_llc llc_ui_addrnull; static struct sockaddr_llc llc_ui_addrnull;
static struct proto_ops llc_ui_ops; static struct proto_ops llc_ui_ops;
static struct sock *llc_ui_sockets; static struct sock *llc_ui_sockets;
...@@ -54,8 +55,16 @@ static rwlock_t llc_ui_sockets_lock = RW_LOCK_UNLOCKED; ...@@ -54,8 +55,16 @@ static rwlock_t llc_ui_sockets_lock = RW_LOCK_UNLOCKED;
static int llc_ui_indicate(struct llc_prim_if_block *prim); static int llc_ui_indicate(struct llc_prim_if_block *prim);
static int llc_ui_confirm(struct llc_prim_if_block *prim); static int llc_ui_confirm(struct llc_prim_if_block *prim);
static int llc_ui_wait_for_conn(struct sock *sk, int seconds); static int llc_ui_wait_for_conn(struct sock *sk, int timeout);
static int llc_ui_wait_for_disc(struct sock *sk, int seconds); static int llc_ui_wait_for_disc(struct sock *sk, int timeout);
static int llc_ui_wait_for_data(struct sock *sk, int timeout);
static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout);
#if 0
#define dprintk(args...) printk(KERN_DEBUG args)
#else
#define dprintk(args...)
#endif
/** /**
* llc_ui_next_link_no - return the next unused link number for a sap * llc_ui_next_link_no - return the next unused link number for a sap
...@@ -63,63 +72,20 @@ static int llc_ui_wait_for_disc(struct sock *sk, int seconds); ...@@ -63,63 +72,20 @@ static int llc_ui_wait_for_disc(struct sock *sk, int seconds);
* *
* Return the next unused link number for a given sap. * Return the next unused link number for a given sap.
*/ */
static inline u16 llc_ui_next_link_no(int sap) static __inline__ u16 llc_ui_next_link_no(int sap)
{ {
return llc_ui_sap_link_no_max[sap]++; return llc_ui_sap_link_no_max[sap]++;
} }
/**
* llc_ui_mac_match - determines if two mac addresses are the same
* @mac1: First mac address to compare.
* @mac2: Second mac address to compare.
*
* Determines if two given mac address are the same. Returns 0 if there
* is not a complete match up to len, 1 if a complete match up to len is
* found.
*/
static inline u8 llc_ui_mac_match(u8 *mac1, u8 *mac2)
{
return !memcmp(mac1, mac2, IFHWADDRLEN);
}
/**
* llc_ui_mac_null - determines if a address is a null mac address
* @mac: Mac address to test if null.
*
* Determines if a given address is a null mac address. Returns 0 if the
* address is not a null mac, 1 if the address is a null mac.
*/
static inline u8 llc_ui_mac_null(u8 *mac)
{
return !memcmp(mac, llc_ui_addrany, IFHWADDRLEN);
}
/** /**
* llc_ui_addr_null - determines if a address structure is null * llc_ui_addr_null - determines if a address structure is null
* @addr: Address to test if null. * @addr: Address to test if null.
*/ */
static inline u8 llc_ui_addr_null(struct sockaddr_llc *addr) static __inline__ u8 llc_ui_addr_null(struct sockaddr_llc *addr)
{ {
return !memcmp(addr, &llc_ui_addrnull, sizeof(*addr)); return !memcmp(addr, &llc_ui_addrnull, sizeof(*addr));
} }
/**
* llc_ui_protocol_type - return eth protocol for ARP header type
* @arphrd: ARP header type.
*
* Given an ARP header type return the corresponding ethernet protocol.
* Returns 0 if ARP header type not supported or the corresponding
* ethernet protocol type.
*/
static inline u16 llc_ui_protocol_type(u16 arphrd)
{
u16 rc = htons(ETH_P_802_2);
if (arphrd == ARPHRD_IEEE802_TR)
rc = htons(ETH_P_TR_802_2);
return rc;
}
/** /**
* llc_ui_header_len - return length of llc header based on operation * llc_ui_header_len - return length of llc header based on operation
* @sk: Socket which contains a valid llc socket type. * @sk: Socket which contains a valid llc socket type.
...@@ -129,7 +95,8 @@ static inline u16 llc_ui_protocol_type(u16 arphrd) ...@@ -129,7 +95,8 @@ static inline u16 llc_ui_protocol_type(u16 arphrd)
* operation the user would like to perform and the type of socket. * operation the user would like to perform and the type of socket.
* Returns the correct llc header length. * Returns the correct llc header length.
*/ */
static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr) static __inline__ u8 llc_ui_header_len(struct sock *sk,
struct sockaddr_llc *addr)
{ {
u8 rc = LLC_PDU_LEN_U; u8 rc = LLC_PDU_LEN_U;
...@@ -140,138 +107,33 @@ static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr) ...@@ -140,138 +107,33 @@ static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr)
return rc; return rc;
} }
/**
* llc_ui_send_conn - send connect command for new llc2 connection
* @sap : Sap the socket is bound to.
* @addr: Source and destination fields provided by the user.
* @dev : Device which this connection should use.
* @link: Link number to assign to this connection.
*
* Send a connect command to the llc layer for a new llc2 connection.
* Returns 0 upon success, non-zero if action didn't succeed.
*/
static int llc_ui_send_conn(struct sock *sk, struct llc_sap *sap,
struct sockaddr_llc *addr,
struct net_device *dev, int link)
{
struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
union llc_u_prim_data prim_data;
struct llc_prim_if_block prim;
prim.data = &prim_data;
prim.sap = sap;
prim.prim = LLC_CONN_PRIM;
prim_data.conn.dev = dev;
prim_data.conn.link = link;
prim_data.conn.sk = NULL;
prim_data.conn.handler = sk;
prim_data.conn.pri = 0;
prim_data.conn.saddr.lsap = llc_ui->addr.sllc_ssap;
prim_data.conn.daddr.lsap = addr->sllc_dsap;
memcpy(prim_data.conn.saddr.mac, dev->dev_addr, IFHWADDRLEN);
memcpy(prim_data.conn.daddr.mac, addr->sllc_dmac, IFHWADDRLEN);
return sap->req(&prim);
}
/**
* llc_ui_send_disc - send disc command to llc layer
* @sk: Socket with valid llc information.
*
* Send a disconnect command to the llc layer for an established
* llc2 connection.
* Returns 0 upon success, non-zero if action did not succeed.
*/
static int llc_ui_send_disc(struct sock *sk)
{
struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
union llc_u_prim_data prim_data;
struct llc_prim_if_block prim;
int rc = 0;
if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED)
goto out;
sk->state = TCP_CLOSING;
prim.data = &prim_data;
prim.sap = llc_ui->sap;
prim.prim = LLC_DISC_PRIM;
prim_data.disc.sk = llc_ui->core_sk;
prim_data.disc.link = llc_ui->link;
rc = llc_ui->sap->req(&prim);
out:
return rc;
}
/** /**
* llc_ui_send_data - send data via reliable llc2 connection * llc_ui_send_data - send data via reliable llc2 connection
* @sap: Sap the socket is bound to.
* @sk: Connection the socket is using. * @sk: Connection the socket is using.
* @skb: Data the user wishes to send. * @skb: Data the user wishes to send.
* @addr: Source and destination fields provided by the user. * @addr: Source and destination fields provided by the user.
* @noblock: can we block waiting for data?
* *
* Send data via reliable llc2 connection. * Send data via reliable llc2 connection.
* Returns 0 upon success, non-zero if action did not succeed. * Returns 0 upon success, non-zero if action did not succeed.
*/ */
static int llc_ui_send_data(struct llc_sap *sap, struct sock* sk, static int llc_ui_send_data(struct sock* sk, struct sk_buff *skb,
struct sk_buff *skb, struct sockaddr_llc *addr) struct sockaddr_llc *addr, int noblock)
{ {
union llc_u_prim_data prim_data; struct llc_opt* llc = llc_sk(sk);
struct llc_prim_if_block prim; int rc = 0;
struct llc_ui_opt* llc_ui = llc_ui_sk(sk);
struct llc_opt* llc_core = llc_sk(llc_ui->core_sk);
int rc;
prim.data = &prim_data; skb->protocol = llc_proto_type(addr->sllc_arphrd);
prim.sap = sap; if (llc_data_accept_state(llc->state) || llc->p_flag) {
prim.prim = LLC_DATA_PRIM; int timeout = sock_sndtimeo(sk, noblock);
prim_data.data.skb = skb;
prim_data.data.pri = 0; rc = llc_ui_wait_for_busy_core(sk, timeout);
prim_data.data.sk = llc_ui->core_sk; }
skb->protocol = llc_ui_protocol_type(addr->sllc_arphrd);
sock_hold(sk);
try:
rc = sap->req(&prim);
if (rc != -EBUSY)
goto out;
rc = wait_event_interruptible(sk->socket->wait, !llc_ui->core_sk ||
!llc_core->failed_data_req);
if (!rc) if (!rc)
goto try; rc = llc_build_and_send_pkt(sk, skb);
if (!llc_ui->core_sk)
rc = -ENOTCONN;
out:
sock_put(sk);
return rc; return rc;
} }
/**
* llc_ui_send_llc1 - send llc1 prim data block to llc layer.
* @sap : Sap the socket is bound to.
* @skb : Data the user wishes to send.
* @addr : Source and destination fields provided by the user.
* @primitive: Action the llc layer should perform.
*
* Send an llc1 primitive data block to the llc layer for processing.
* This function is used for test, xid and unit_data messages.
* Returns 0 upon success, non-zero if action did not succeed.
*/
static int llc_ui_send_llc1(struct llc_sap *sap, struct sk_buff *skb,
struct sockaddr_llc *addr, int primitive)
{
union llc_u_prim_data prim_data;
struct llc_prim_if_block prim;
prim.data = &prim_data;
prim.sap = sap;
prim.prim = primitive;
prim_data.test.skb = skb;
prim_data.test.saddr.lsap = sap->laddr.lsap;
prim_data.test.daddr.lsap = addr->sllc_dsap;
skb->protocol = llc_ui_protocol_type(addr->sllc_arphrd);
memcpy(prim_data.test.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN);
memcpy(prim_data.test.daddr.mac, addr->sllc_dmac, IFHWADDRLEN);
return sap->req(&prim);
}
/** /**
* llc_ui_find_sap - returns sap struct that matches sap number specified * llc_ui_find_sap - returns sap struct that matches sap number specified
* @sap: Sap number to search for. * @sap: Sap number to search for.
...@@ -280,19 +142,19 @@ static int llc_ui_send_llc1(struct llc_sap *sap, struct sk_buff *skb, ...@@ -280,19 +142,19 @@ static int llc_ui_send_llc1(struct llc_sap *sap, struct sk_buff *skb,
* structure which matches the sap number the user specified. * structure which matches the sap number the user specified.
* Returns llc_sap upon match, %NULL otherwise. * Returns llc_sap upon match, %NULL otherwise.
*/ */
static inline struct llc_sap *llc_ui_find_sap(u8 sap) static __inline__ struct llc_sap *llc_ui_find_sap(u8 sap)
{ {
struct sock *sk; struct sock *sk;
struct llc_sap *s = NULL; struct llc_sap *s = NULL;
read_lock_bh(&llc_ui_sockets_lock); read_lock_bh(&llc_ui_sockets_lock);
for (sk = llc_ui_sockets; sk; sk = sk->next) { for (sk = llc_ui_sockets; sk; sk = sk->next) {
struct llc_ui_opt *llc_ui = llc_ui_sk(sk); struct llc_opt *llc = llc_sk(sk);
if (!llc_ui->sap) if (!llc->sap)
continue; continue;
if (llc_ui->sap->laddr.lsap == sap) { if (llc->sap->laddr.lsap == sap) {
s = llc_ui->sap; s = llc->sap;
break; break;
} }
} }
...@@ -306,13 +168,13 @@ static struct sock *__llc_ui_find_sk_by_exact(struct llc_addr *laddr, ...@@ -306,13 +168,13 @@ static struct sock *__llc_ui_find_sk_by_exact(struct llc_addr *laddr,
struct sock *sk; struct sock *sk;
for (sk = llc_ui_sockets; sk; sk = sk->next) { for (sk = llc_ui_sockets; sk; sk = sk->next) {
struct llc_ui_opt *llc_ui = llc_ui_sk(sk); struct llc_opt *llc = llc_sk(sk);
if (llc_ui->addr.sllc_ssap == laddr->lsap && if (llc->addr.sllc_ssap == laddr->lsap &&
llc_ui->addr.sllc_dsap == daddr->lsap && llc->addr.sllc_dsap == daddr->lsap &&
llc_ui_mac_null(llc_ui->addr.sllc_mmac) && llc_mac_null(llc->addr.sllc_mmac) &&
llc_ui_mac_match(llc_ui->addr.sllc_smac, laddr->mac) && llc_mac_match(llc->addr.sllc_smac, laddr->mac) &&
llc_ui_mac_match(llc_ui->addr.sllc_dmac, daddr->mac)) llc_mac_match(llc->addr.sllc_dmac, daddr->mac))
break; break;
} }
return sk; return sk;
...@@ -335,31 +197,31 @@ static struct sock *__llc_ui_find_sk_by_addr(struct llc_addr *laddr, ...@@ -335,31 +197,31 @@ static struct sock *__llc_ui_find_sk_by_addr(struct llc_addr *laddr,
struct sock *sk, *tmp_sk; struct sock *sk, *tmp_sk;
for (sk = llc_ui_sockets; sk; sk = sk->next) { for (sk = llc_ui_sockets; sk; sk = sk->next) {
struct llc_ui_opt *llc_ui = llc_ui_sk(sk); struct llc_opt *llc = llc_sk(sk);
if (llc_ui->addr.sllc_ssap != laddr->lsap) if (llc->addr.sllc_ssap != laddr->lsap)
continue; continue;
if (llc_ui_mac_null(llc_ui->addr.sllc_smac)) { if (llc_mac_null(llc->addr.sllc_smac)) {
if (!llc_ui_mac_null(llc_ui->addr.sllc_mmac) && if (!llc_mac_null(llc->addr.sllc_mmac) &&
!llc_ui_mac_match(llc_ui->addr.sllc_mmac, !llc_mac_match(llc->addr.sllc_mmac,
laddr->mac)) laddr->mac))
continue; continue;
break; break;
} }
if (dev && !llc_ui_mac_null(llc_ui->addr.sllc_mmac) && if (dev && !llc_mac_null(llc->addr.sllc_mmac) &&
llc_ui_mac_match(llc_ui->addr.sllc_mmac, laddr->mac) && llc_mac_match(llc->addr.sllc_mmac, laddr->mac) &&
llc_ui_mac_match(llc_ui->addr.sllc_smac, dev->dev_addr)) llc_mac_match(llc->addr.sllc_smac, dev->dev_addr))
break; break;
if (dev->flags & IFF_LOOPBACK) if (dev->flags & IFF_LOOPBACK)
break; break;
if (!llc_ui_mac_match(llc_ui->addr.sllc_smac, laddr->mac)) if (!llc_mac_match(llc->addr.sllc_smac, laddr->mac))
continue; continue;
tmp_sk = __llc_ui_find_sk_by_exact(laddr, daddr); tmp_sk = __llc_ui_find_sk_by_exact(laddr, daddr);
if (tmp_sk) { if (tmp_sk) {
sk = tmp_sk; sk = tmp_sk;
break; break;
} }
if (llc_ui_mac_null(llc_ui->addr.sllc_dmac)) if (llc_mac_null(llc->addr.sllc_dmac))
break; break;
} }
return sk; return sk;
...@@ -399,7 +261,7 @@ static struct sock *llc_ui_bh_find_sk_by_addr(struct llc_addr *addr, ...@@ -399,7 +261,7 @@ static struct sock *llc_ui_bh_find_sk_by_addr(struct llc_addr *addr,
* *
* Insert a socket into the local llc socket list. * Insert a socket into the local llc socket list.
*/ */
static inline void llc_ui_insert_socket(struct sock *sk) static __inline__ void llc_ui_insert_socket(struct sock *sk)
{ {
write_lock_bh(&llc_ui_sockets_lock); write_lock_bh(&llc_ui_sockets_lock);
sk->next = llc_ui_sockets; sk->next = llc_ui_sockets;
...@@ -417,7 +279,7 @@ static inline void llc_ui_insert_socket(struct sock *sk) ...@@ -417,7 +279,7 @@ static inline void llc_ui_insert_socket(struct sock *sk)
* *
* Remove a socket from the local llc socket list. * Remove a socket from the local llc socket list.
*/ */
static inline void llc_ui_remove_socket(struct sock *sk) static __inline__ void llc_ui_remove_socket(struct sock *sk)
{ {
write_lock_bh(&llc_ui_sockets_lock); write_lock_bh(&llc_ui_sockets_lock);
if (sk->pprev) { if (sk->pprev) {
...@@ -425,7 +287,8 @@ static inline void llc_ui_remove_socket(struct sock *sk) ...@@ -425,7 +287,8 @@ static inline void llc_ui_remove_socket(struct sock *sk)
sk->next->pprev = sk->pprev; sk->next->pprev = sk->pprev;
*sk->pprev = sk->next; *sk->pprev = sk->next;
sk->pprev = NULL; sk->pprev = NULL;
/* this only makes sense if the socket was inserted on the /*
* This only makes sense if the socket was inserted on the
* list, if sk->pprev is NULL it wasn't * list, if sk->pprev is NULL it wasn't
*/ */
sock_put(sk); sock_put(sk);
...@@ -433,38 +296,13 @@ static inline void llc_ui_remove_socket(struct sock *sk) ...@@ -433,38 +296,13 @@ static inline void llc_ui_remove_socket(struct sock *sk)
write_unlock_bh(&llc_ui_sockets_lock); write_unlock_bh(&llc_ui_sockets_lock);
} }
/** static void llc_ui_sk_init(struct socket *sock, struct sock *sk)
* llc_ui_destroy_sk - destroy socket
* @data: Socket which is to be destroyed.
*
* Really destroy the socket.
*/
static void llc_ui_destroy_sk(struct sock *sk)
{
skb_queue_purge(&sk->receive_queue);
skb_queue_purge(&sk->write_queue);
sock_put(sk);
MOD_DEC_USE_COUNT;
}
/**
* llc_ui_destroy_timer - try to destroy socket again
* @data: Socket which is to be destroyed.
*
* Attempt to destroy a socket which was previously destroyed but
* was still in use at the time.
*/
static void llc_ui_destroy_timer(unsigned long data)
{ {
struct sock *sk = (struct sock *)data; sk->type = sock->type;
sk->sleep = &sock->wait;
if (!atomic_read(&sk->wmem_alloc) && sk->socket = sock;
!atomic_read(&sk->rmem_alloc) && sk->dead) sock->sk = sk;
llc_ui_destroy_sk(sk); sock->ops = &llc_ui_ops;
else {
sk->timer.expires = jiffies + SOCK_DESTROY_TIME;
add_timer(&sk->timer);
}
} }
/** /**
...@@ -479,31 +317,17 @@ static void llc_ui_destroy_timer(unsigned long data) ...@@ -479,31 +317,17 @@ static void llc_ui_destroy_timer(unsigned long data)
static int llc_ui_create(struct socket *sock, int protocol) static int llc_ui_create(struct socket *sock, int protocol)
{ {
struct sock *sk; struct sock *sk;
struct llc_ui_opt *llc_ui;
int rc = -ESOCKTNOSUPPORT; int rc = -ESOCKTNOSUPPORT;
MOD_INC_USE_COUNT; if (sock->type == SOCK_DGRAM || sock->type == SOCK_STREAM) {
if (sock->type != SOCK_DGRAM && sock->type != SOCK_STREAM) rc = -ENOMEM;
goto decmod; sk = llc_sk_alloc(PF_LLC, GFP_KERNEL);
rc = -ENOMEM; if (sk) {
sk = sk_alloc(PF_LLC, GFP_KERNEL, 1, NULL); rc = 0;
if (!sk) llc_ui_sk_init(sock, sk);
goto decmod; }
llc_ui = kmalloc(sizeof(*llc_ui), GFP_KERNEL); }
if (!llc_ui)
goto outsk;
memset(llc_ui, 0, sizeof(*llc_ui));
rc = 0;
sock_init_data(sock, sk);
llc_ui_sk(sk) = llc_ui;
sock->ops = &llc_ui_ops;
out:
return rc; return rc;
outsk:
sk_free(sk);
decmod:
MOD_DEC_USE_COUNT;
goto out;
} }
/** /**
...@@ -515,28 +339,26 @@ static int llc_ui_create(struct socket *sock, int protocol) ...@@ -515,28 +339,26 @@ static int llc_ui_create(struct socket *sock, int protocol)
static int llc_ui_release(struct socket *sock) static int llc_ui_release(struct socket *sock)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct llc_ui_opt *llc_ui; struct llc_opt *llc;
if (!sk) if (!sk)
goto out; goto out;
llc_ui = llc_ui_sk(sk); sock_hold(sk);
if (llc_ui->core_sk && !llc_ui_send_disc(sk)) lock_sock(sk);
llc_ui_wait_for_disc(sk, 255); llc = llc_sk(sk);
llc_ui_remove_socket(sk); dprintk("%s: closing local(%02X) remote(%02X)\n", __FUNCTION__,
if (llc_ui->sap && !llc_ui_find_sap(llc_ui->sap->laddr.lsap)) llc->laddr.lsap, llc->daddr.lsap);
llc_sap_close(llc_ui->sap); if (!llc_send_disc(sk))
sock_orphan(sk); llc_ui_wait_for_disc(sk, sk->rcvtimeo);
sock->sk = NULL; release_sock(sk);
if (!atomic_read(&sk->wmem_alloc) && if (!sk->zapped) {
!atomic_read(&sk->rmem_alloc) && sk->dead) llc_sap_unassign_sock(llc->sap, sk);
llc_ui_destroy_sk(sk); llc_ui_remove_socket(sk);
else {
init_timer(&sk->timer);
sk->timer.expires = jiffies + SOCK_DESTROY_TIME;
sk->timer.function = llc_ui_destroy_timer;
sk->timer.data = (unsigned long)sk;
add_timer(&sk->timer);
} }
if (llc->sap && list_empty(&llc->sap->sk_list.list))
llc_sap_close(llc->sap);
sock_put(sk);
llc_sk_free(sk);
out: out:
return 0; return 0;
} }
...@@ -590,7 +412,7 @@ static int llc_ui_autoport(void) ...@@ -590,7 +412,7 @@ static int llc_ui_autoport(void)
static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct llc_ui_opt *llc_ui = llc_ui_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap; struct llc_sap *sap;
struct net_device *dev = NULL; struct net_device *dev = NULL;
int rc = -EINVAL; int rc = -EINVAL;
...@@ -598,14 +420,14 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) ...@@ -598,14 +420,14 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
if (!sk->zapped) if (!sk->zapped)
goto out; goto out;
/* bind to a specific mac, optional. */ /* bind to a specific mac, optional. */
if (!llc_ui_mac_null(addr->sllc_smac)) { if (!llc_mac_null(addr->sllc_smac)) {
rtnl_lock(); rtnl_lock();
dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac); dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac);
rtnl_unlock(); rtnl_unlock();
rc = -ENETUNREACH; rc = -ENETUNREACH;
if (!dev) if (!dev)
goto out; goto out;
llc_ui->dev = dev; llc->dev = dev;
} }
/* bind to a specific sap, optional. */ /* bind to a specific sap, optional. */
if (!addr->sllc_ssap) { if (!addr->sllc_ssap) {
...@@ -626,11 +448,11 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) ...@@ -626,11 +448,11 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
struct sock *ask; struct sock *ask;
rc = -EUSERS; /* can't get exclusive use of sap */ rc = -EUSERS; /* can't get exclusive use of sap */
if (!dev && llc_ui_mac_null(addr->sllc_mmac)) if (!dev && llc_mac_null(addr->sllc_mmac))
goto out; goto out;
memset(&laddr, 0, sizeof(laddr)); memset(&laddr, 0, sizeof(laddr));
memset(&daddr, 0, sizeof(daddr)); memset(&daddr, 0, sizeof(daddr));
if (!llc_ui_mac_null(addr->sllc_mmac)) { if (!llc_mac_null(addr->sllc_mmac)) {
if (sk->type != SOCK_DGRAM) { if (sk->type != SOCK_DGRAM) {
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
goto out; goto out;
...@@ -646,10 +468,16 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) ...@@ -646,10 +468,16 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
goto out; goto out;
} }
} }
memcpy(&llc_ui->addr, addr, sizeof(*addr)); llc->laddr.lsap = addr->sllc_ssap;
llc_ui->sap = sap; if (llc->dev)
memcpy(llc->laddr.mac, llc->dev->dev_addr, IFHWADDRLEN);
llc->daddr.lsap = addr->sllc_dsap;
memcpy(llc->daddr.mac, addr->sllc_dmac, IFHWADDRLEN);
memcpy(&llc->addr, addr, sizeof(llc->addr));
rc = sk->zapped = 0; rc = sk->zapped = 0;
llc_ui_insert_socket(sk); llc_ui_insert_socket(sk);
/* assign new connection to it's SAP */
llc_sap_assign_sock(sap, sk);
out: out:
return rc; return rc;
} }
...@@ -678,6 +506,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) ...@@ -678,6 +506,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
int rc = -EINVAL; int rc = -EINVAL;
dprintk("%s: binding %02X\n", __FUNCTION__, addr->sllc_ssap);
if (!sk->zapped || addrlen != sizeof(*addr)) if (!sk->zapped || addrlen != sizeof(*addr))
goto out; goto out;
rc = -EAFNOSUPPORT; rc = -EAFNOSUPPORT;
...@@ -711,9 +540,9 @@ static int llc_ui_shutdown(struct socket *sock, int how) ...@@ -711,9 +540,9 @@ static int llc_ui_shutdown(struct socket *sock, int how)
rc = -EINVAL; rc = -EINVAL;
if (how != 2) if (how != 2)
goto out; goto out;
rc = llc_ui_send_disc(sk); rc = llc_send_disc(sk);
if (!rc) if (!rc)
llc_ui_wait_for_disc(sk, 255); rc = llc_ui_wait_for_disc(sk, sk->rcvtimeo);
/* Wake up anyone sleeping in poll */ /* Wake up anyone sleeping in poll */
sk->state_change(sk); sk->state_change(sk);
out: out:
...@@ -739,7 +568,7 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr, ...@@ -739,7 +568,7 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
int addrlen, int flags) int addrlen, int flags)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct llc_ui_opt *llc_ui = llc_ui_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr; struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr;
struct net_device *dev; struct net_device *dev;
int rc = -EINVAL; int rc = -EINVAL;
...@@ -757,14 +586,15 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr, ...@@ -757,14 +586,15 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
if (rc) if (rc)
goto out; goto out;
} }
if (!llc_ui->dev) { if (!llc->dev) {
rtnl_lock(); rtnl_lock();
dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac); dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac);
rtnl_unlock(); rtnl_unlock();
if (!dev) if (!dev)
goto out; goto out;
llc->dev = dev;
} else } else
dev = llc_ui->dev; dev = llc->dev;
if (sk->type != SOCK_STREAM) if (sk->type != SOCK_STREAM)
goto out; goto out;
rc = -EALREADY; rc = -EALREADY;
...@@ -772,14 +602,18 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr, ...@@ -772,14 +602,18 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
goto out; goto out;
sock->state = SS_CONNECTING; sock->state = SS_CONNECTING;
sk->state = TCP_SYN_SENT; sk->state = TCP_SYN_SENT;
llc_ui->link = llc_ui_next_link_no(llc_ui->sap->laddr.lsap); llc->link = llc_ui_next_link_no(llc->sap->laddr.lsap);
rc = llc_ui_send_conn(sk, llc_ui->sap, addr, dev, llc_ui->link); rc = llc_establish_connection(sk, dev->dev_addr,
addr->sllc_dmac, addr->sllc_dsap);
if (rc) { if (rc) {
dprintk("%s: llc_ui_send_conn failed :-(\n", __FUNCTION__);
sock->state = SS_UNCONNECTED; sock->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE; sk->state = TCP_CLOSE;
goto out; goto out;
} }
rc = llc_ui_wait_for_conn(sk, 255); rc = llc_ui_wait_for_conn(sk, sk->rcvtimeo);
if (rc)
dprintk("%s: llc_ui_wait_for_conn failed=%d\n", __FUNCTION__, rc);
out: out:
release_sock(sk); release_sock(sk);
return rc; return rc;
...@@ -802,7 +636,7 @@ static int llc_ui_listen(struct socket *sock, int backlog) ...@@ -802,7 +636,7 @@ static int llc_ui_listen(struct socket *sock, int backlog)
if (sock->state != SS_UNCONNECTED) if (sock->state != SS_UNCONNECTED)
goto out; goto out;
rc = -EOPNOTSUPP; rc = -EOPNOTSUPP;
if (sk->type != SOCK_STREAM && sk->type != SOCK_SEQPACKET) if (sk->type != SOCK_STREAM)
goto out; goto out;
rc = -EAGAIN; rc = -EAGAIN;
if (sk->zapped) if (sk->zapped)
...@@ -810,8 +644,6 @@ static int llc_ui_listen(struct socket *sock, int backlog) ...@@ -810,8 +644,6 @@ static int llc_ui_listen(struct socket *sock, int backlog)
rc = 0; rc = 0;
if (!(unsigned)backlog) /* BSDism */ if (!(unsigned)backlog) /* BSDism */
backlog = 1; backlog = 1;
if ((unsigned)backlog > SOMAXCONN)
backlog = SOMAXCONN;
sk->max_ack_backlog = backlog; sk->max_ack_backlog = backlog;
if (sk->state != TCP_LISTEN) { if (sk->state != TCP_LISTEN) {
sk->ack_backlog = 0; sk->ack_backlog = 0;
...@@ -823,18 +655,43 @@ static int llc_ui_listen(struct socket *sock, int backlog) ...@@ -823,18 +655,43 @@ static int llc_ui_listen(struct socket *sock, int backlog)
return rc; return rc;
} }
static int llc_ui_wait_for_disc(struct sock *sk, int seconds) static int llc_ui_wait_for_disc(struct sock *sk, int timeout)
{ {
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
int rc, timeout = seconds * HZ; int rc;
add_wait_queue_exclusive(sk->sleep, &wait); add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) { for (;;) {
__set_current_state(TASK_INTERRUPTIBLE); __set_current_state(TASK_INTERRUPTIBLE);
rc = -ERESTARTSYS;
if (signal_pending(current))
break;
rc = -EAGAIN;
if (!timeout)
break;
rc = 0; rc = 0;
if (sk->state != TCP_CLOSE) if (sk->state != TCP_CLOSE) {
release_sock(sk);
timeout = schedule_timeout(timeout); timeout = schedule_timeout(timeout);
else lock_sock(sk);
} else
break;
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(sk->sleep, &wait);
return rc;
}
static int llc_ui_wait_for_conn(struct sock *sk, int timeout)
{
DECLARE_WAITQUEUE(wait, current);
int rc;
add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
rc = -EAGAIN;
if (sk->state == TCP_CLOSE)
break; break;
rc = -ERESTARTSYS; rc = -ERESTARTSYS;
if (signal_pending(current)) if (signal_pending(current))
...@@ -842,31 +699,60 @@ static int llc_ui_wait_for_disc(struct sock *sk, int seconds) ...@@ -842,31 +699,60 @@ static int llc_ui_wait_for_disc(struct sock *sk, int seconds)
rc = -EAGAIN; rc = -EAGAIN;
if (!timeout) if (!timeout)
break; break;
rc = 0;
if (sk->state != TCP_ESTABLISHED) {
release_sock(sk);
timeout = schedule_timeout(timeout);
lock_sock(sk);
} else
break;
} }
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
remove_wait_queue(sk->sleep, &wait); remove_wait_queue(sk->sleep, &wait);
return rc; return rc;
} }
static int llc_ui_wait_for_conn(struct sock *sk, int seconds) static int llc_ui_wait_for_data(struct sock *sk, int timeout)
{ {
struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
DECLARE_WAITQUEUE(wait, current); DECLARE_WAITQUEUE(wait, current);
int rc, timeout = seconds * HZ; int rc = 0;
add_wait_queue_exclusive(sk->sleep, &wait); add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) { for (;;) {
__set_current_state(TASK_INTERRUPTIBLE); __set_current_state(TASK_INTERRUPTIBLE);
if (sk->shutdown & RCV_SHUTDOWN)
break;
rc = -ERESTARTSYS;
if (signal_pending(current))
break;
rc = -EAGAIN;
if (!timeout)
break;
rc = 0; rc = 0;
if (sk->state != TCP_ESTABLISHED) if (skb_queue_empty(&sk->receive_queue)) {
release_sock(sk);
timeout = schedule_timeout(timeout); timeout = schedule_timeout(timeout);
if (sk->state == TCP_ESTABLISHED) { lock_sock(sk);
if (!llc_ui->core_sk) } else
rc = -EAGAIN;
break; break;
} }
rc = -EAGAIN; __set_current_state(TASK_RUNNING);
if (sk->state == TCP_CLOSE) remove_wait_queue(sk->sleep, &wait);
return rc;
}
static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout)
{
DECLARE_WAITQUEUE(wait, current);
struct llc_opt *llc = llc_sk(sk);
int rc;
add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) {
dprintk("%s: looping...\n", __FUNCTION__);
__set_current_state(TASK_INTERRUPTIBLE);
rc = -ENOTCONN;
if (sk->shutdown & RCV_SHUTDOWN)
break; break;
rc = -ERESTARTSYS; rc = -ERESTARTSYS;
if (signal_pending(current)) if (signal_pending(current))
...@@ -874,6 +760,13 @@ static int llc_ui_wait_for_conn(struct sock *sk, int seconds) ...@@ -874,6 +760,13 @@ static int llc_ui_wait_for_conn(struct sock *sk, int seconds)
rc = -EAGAIN; rc = -EAGAIN;
if (!timeout) if (!timeout)
break; break;
rc = 0;
if (llc_data_accept_state(llc->state) || llc->p_flag) {
release_sock(sk);
timeout = schedule_timeout(timeout);
lock_sock(sk);
} else
break;
} }
__set_current_state(TASK_RUNNING); __set_current_state(TASK_RUNNING);
remove_wait_queue(sk->sleep, &wait); remove_wait_queue(sk->sleep, &wait);
...@@ -892,63 +785,48 @@ static int llc_ui_wait_for_conn(struct sock *sk, int seconds) ...@@ -892,63 +785,48 @@ static int llc_ui_wait_for_conn(struct sock *sk, int seconds)
static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags) static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags)
{ {
struct sock *sk = sock->sk, *newsk; struct sock *sk = sock->sk, *newsk;
struct llc_ui_opt *llc_ui, *newllc_ui; struct llc_opt *llc, *newllc;
struct llc_opt *newllc_core;
struct sk_buff *skb; struct sk_buff *skb;
int rc = -EOPNOTSUPP; int rc = -EOPNOTSUPP;
dprintk("%s: accepting on %02X\n", __FUNCTION__, llc_sk(sk)->addr.sllc_ssap);
lock_sock(sk); lock_sock(sk);
if (sk->type != SOCK_SEQPACKET && sk->type != SOCK_STREAM) if (sk->type != SOCK_STREAM)
goto out; goto out;
rc = -EINVAL; rc = -EINVAL;
if (sock->state != SS_UNCONNECTED || sk->state != TCP_LISTEN) if (sock->state != SS_UNCONNECTED || sk->state != TCP_LISTEN)
goto out; goto out;
/* wait for a connection to arrive. */ /* wait for a connection to arrive. */
do { rc = llc_ui_wait_for_data(sk, sk->rcvtimeo);
skb = skb_dequeue(&sk->receive_queue);
if (!skb) {
rc = -EWOULDBLOCK;
if (flags & O_NONBLOCK)
goto out;
interruptible_sleep_on(sk->sleep);
rc = -ERESTARTSYS;
if (signal_pending(current))
goto out;
}
} while (!skb);
rc = -EINVAL;
if(!skb->sk)
goto frees;
/* attach connection to a new socket. */
rc = llc_ui_create(newsock, sk->protocol);
if (rc) if (rc)
goto out;
dprintk("%s: got a new connection on %02X\n", __FUNCTION__, llc_sk(sk)->addr.sllc_ssap);
skb = skb_dequeue(&sk->receive_queue);
rc = -EINVAL;
if (!skb->sk)
goto frees; goto frees;
rc = 0; rc = 0;
newsk = newsock->sk; newsk = skb->sk;
/* attach connection to a new socket. */
llc_ui_sk_init(newsock, newsk);
newsk->pair = NULL; newsk->pair = NULL;
newsk->socket = newsock;
newsk->sleep = &newsock->wait;
newsk->zapped = 0; newsk->zapped = 0;
newsk->state = TCP_ESTABLISHED; newsk->state = TCP_ESTABLISHED;
newsock->state = SS_CONNECTED; newsock->state = SS_CONNECTED;
llc_ui = llc_ui_sk(sk); llc = llc_sk(sk);
newllc_ui = llc_ui_sk(newsk); newllc = llc_sk(newsk);
newllc_ui->sap = llc_ui->sap; memcpy(&newllc->addr, &llc->addr, sizeof(newllc->addr));
newllc_ui->dev = llc_ui->dev; memcpy(newllc->addr.sllc_dmac, newllc->daddr.mac, IFHWADDRLEN);
newllc_ui->core_sk = skb->sk; newllc->addr.sllc_dsap = newllc->daddr.lsap;
newllc_core = llc_sk(newllc_ui->core_sk); newllc->link = llc_ui_next_link_no(newllc->laddr.lsap);
newllc_ui->link = newllc_core->link;
newllc_core->handler = newsk;
memcpy(&newllc_ui->addr, &llc_ui->addr, sizeof(newllc_ui->addr));
memcpy(newllc_ui->addr.sllc_dmac, newllc_core->daddr.mac, IFHWADDRLEN);
newllc_ui->addr.sllc_dsap = newllc_core->daddr.lsap;
/* put original socket back into a clean listen state. */ /* put original socket back into a clean listen state. */
sk->state = TCP_LISTEN; sk->state = TCP_LISTEN;
sk->ack_backlog--; sk->ack_backlog--;
llc_ui_insert_socket(newsk); llc_ui_insert_socket(newsk);
skb->sk = NULL; skb->sk = NULL;
dprintk("%s: ok success on %02X, client on %02X\n", __FUNCTION__,
llc_sk(sk)->addr.sllc_ssap, newllc->addr.sllc_dsap);
frees: frees:
kfree_skb(skb); kfree_skb(skb);
out: out:
...@@ -973,12 +851,21 @@ static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, int size, ...@@ -973,12 +851,21 @@ static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, int size,
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name; struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name;
struct sk_buff *skb; struct sk_buff *skb;
int rc = -ENOMEM, copied = 0; int rc = -ENOMEM, copied = 0, timeout;
int noblock = flags & MSG_DONTWAIT; int noblock = flags & MSG_DONTWAIT;
dprintk("%s: receiving in %02X from %02X\n", __FUNCTION__,
llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap);
lock_sock(sk); lock_sock(sk);
skb = skb_recv_datagram(sk, flags, noblock, &rc); timeout = sock_rcvtimeo(sk, noblock);
if (!skb) rc = llc_ui_wait_for_data(sk, timeout);
if (rc) {
dprintk("%s: llc_ui_wait_for_data failed recv in %02X from %02X\n",
__FUNCTION__, llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap);
goto out;
}
skb = skb_dequeue(&sk->receive_queue);
if (!skb) /* shutdown */
goto out; goto out;
copied = skb->len; copied = skb->len;
if (copied > size) { if (copied > size) {
...@@ -992,7 +879,7 @@ static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, int size, ...@@ -992,7 +879,7 @@ static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, int size,
memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr)); memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr));
msg->msg_namelen = sizeof(*uaddr); msg->msg_namelen = sizeof(*uaddr);
dgram_free: dgram_free:
skb_free_datagram(sk, skb); /* Free the datagram. */ kfree_skb(skb);
out: out:
release_sock(sk); release_sock(sk);
return rc ? : copied; return rc ? : copied;
...@@ -1012,24 +899,23 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len, ...@@ -1012,24 +899,23 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
struct scm_cookie *scm) struct scm_cookie *scm)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct llc_ui_opt *llc_ui = llc_ui_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct sockaddr_llc *addr = (struct sockaddr_llc *)msg->msg_name; struct sockaddr_llc *addr = (struct sockaddr_llc *)msg->msg_name;
int flags = msg->msg_flags; int flags = msg->msg_flags;
int noblock = flags & MSG_DONTWAIT;
struct net_device *dev; struct net_device *dev;
struct sk_buff *skb; struct sk_buff *skb;
int rc = -EOPNOTSUPP, size = 0; int rc = -EINVAL, size = 0;
dprintk("%s: sending from %02X to %02X\n", __FUNCTION__, llc->laddr.lsap, llc->daddr.lsap);
lock_sock(sk); lock_sock(sk);
if (flags & ~MSG_DONTWAIT)
goto release;
rc = -EINVAL;
if (addr) { if (addr) {
if (msg->msg_namelen < sizeof(*addr)) if (msg->msg_namelen < sizeof(*addr))
goto release; goto release;
} else { } else {
if (llc_ui_addr_null(&llc_ui->addr)) if (llc_ui_addr_null(&llc->addr))
goto release; goto release;
addr = &llc_ui->addr; addr = &llc->addr;
} }
/* must bind connection to sap if user hasn't done it. */ /* must bind connection to sap if user hasn't done it. */
if (sk->zapped) { if (sk->zapped) {
...@@ -1038,7 +924,7 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len, ...@@ -1038,7 +924,7 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
if (rc) if (rc)
goto release; goto release;
} }
if (!llc_ui->dev) { if (!llc->dev) {
rtnl_lock(); rtnl_lock();
dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac); dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac);
rtnl_unlock(); rtnl_unlock();
...@@ -1046,12 +932,12 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len, ...@@ -1046,12 +932,12 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
if (!dev) if (!dev)
goto release; goto release;
} else } else
dev = llc_ui->dev; dev = llc->dev;
size = dev->hard_header_len + len + llc_ui_header_len(sk, addr); size = dev->hard_header_len + len + llc_ui_header_len(sk, addr);
rc = -EMSGSIZE; rc = -EMSGSIZE;
if (size > dev->mtu) if (size > dev->mtu)
goto release; goto release;
skb = sock_alloc_send_skb(sk, size, flags & MSG_DONTWAIT, &rc); skb = sock_alloc_send_skb(sk, size, noblock, &rc);
if (!skb) if (!skb)
goto release; goto release;
skb->sk = sk; skb->sk = sk;
...@@ -1059,30 +945,32 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len, ...@@ -1059,30 +945,32 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
skb_reserve(skb, dev->hard_header_len + llc_ui_header_len(sk, addr)); skb_reserve(skb, dev->hard_header_len + llc_ui_header_len(sk, addr));
rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
if (rc) if (rc)
goto release; goto out;
if (addr->sllc_test) { if (addr->sllc_test) {
rc = llc_ui_send_llc1(llc_ui->sap, skb, addr, LLC_TEST_PRIM); llc_build_and_send_test_pkt(llc->sap, skb, addr);
goto out; goto out;
} }
if (addr->sllc_xid) { if (addr->sllc_xid) {
rc = llc_ui_send_llc1(llc_ui->sap, skb, addr, LLC_XID_PRIM); llc_build_and_send_xid_pkt(llc->sap, skb, addr);
goto out; goto out;
} }
if (sk->type == SOCK_DGRAM || addr->sllc_ua) { if (sk->type == SOCK_DGRAM || addr->sllc_ua) {
rc = llc_ui_send_llc1(llc_ui->sap, skb, addr, LLC_DATAUNIT_PRIM); llc_build_and_send_ui_pkt(llc->sap, skb, addr);
goto out; goto out;
} }
rc = -ENOPROTOOPT; rc = -ENOPROTOOPT;
if (!(sk->type == SOCK_STREAM && !addr->sllc_ua)) if (!(sk->type == SOCK_STREAM && !addr->sllc_ua))
goto out; goto out;
rc = -ENOTCONN; rc = llc_ui_send_data(sk, skb, addr, noblock);
if (!llc_ui->core_sk) if (rc)
goto out; dprintk("%s: llc_ui_send_data failed: %d\n", __FUNCTION__, rc);
rc = llc_ui_send_data(llc_ui->sap, sk, skb, addr);
out: out:
if (rc) if (rc)
skb_free_datagram(sk, skb); kfree_skb(skb);
release: release:
if (rc)
dprintk("%s: failed sending from %02X to %02X: %d\n",
__FUNCTION__, llc->laddr.lsap, llc->daddr.lsap, rc);
release_sock(sk); release_sock(sk);
return rc ? : len; return rc ? : len;
} }
...@@ -1101,7 +989,7 @@ static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr, ...@@ -1101,7 +989,7 @@ static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr,
{ {
struct sockaddr_llc sllc; struct sockaddr_llc sllc;
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct llc_ui_opt *llc_ui = llc_ui_sk(sk); struct llc_opt *llc = llc_sk(sk);
int rc = 0; int rc = 0;
lock_sock(sk); lock_sock(sk);
...@@ -1113,20 +1001,19 @@ static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr, ...@@ -1113,20 +1001,19 @@ static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr,
rc = -ENOTCONN; rc = -ENOTCONN;
if (sk->state != TCP_ESTABLISHED) if (sk->state != TCP_ESTABLISHED)
goto out; goto out;
if(llc_ui->dev) if(llc->dev)
sllc.sllc_arphrd = llc_ui->dev->type; sllc.sllc_arphrd = llc->dev->type;
sllc.sllc_dsap = llc_sk(llc_ui->core_sk)->daddr.lsap; sllc.sllc_dsap = llc->daddr.lsap;
memcpy(&sllc.sllc_dmac, &llc_sk(llc_ui->core_sk)->daddr.mac, memcpy(&sllc.sllc_dmac, &llc->daddr.mac, IFHWADDRLEN);
IFHWADDRLEN);
} else { } else {
rc = -EINVAL; rc = -EINVAL;
if (!llc_ui->sap) if (!llc->sap)
goto out; goto out;
sllc.sllc_ssap = llc_ui->sap->laddr.lsap; sllc.sllc_ssap = llc->sap->laddr.lsap;
if (llc_ui->dev) { if (llc->dev) {
sllc.sllc_arphrd = llc_ui->dev->type; sllc.sllc_arphrd = llc->dev->type;
memcpy(&sllc.sllc_smac, &llc_ui->dev->dev_addr, memcpy(&sllc.sllc_smac, &llc->dev->dev_addr,
IFHWADDRLEN); IFHWADDRLEN);
} }
} }
...@@ -1166,61 +1053,56 @@ static int llc_ui_setsockopt(struct socket *sock, int level, int optname, ...@@ -1166,61 +1053,56 @@ static int llc_ui_setsockopt(struct socket *sock, int level, int optname,
char *optval, int optlen) char *optval, int optlen)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct llc_ui_opt *llc_ui = llc_ui_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_opt *llc_core;
int rc = -EINVAL, opt; int rc = -EINVAL, opt;
lock_sock(sk); lock_sock(sk);
if (level != SOL_LLC || optlen != sizeof(int)) if (level != SOL_LLC || optlen != sizeof(int))
goto out; goto out;
rc = -ENOTCONN;
if (!llc_ui->core_sk)
goto out;
rc = get_user(opt, (int *)optval); rc = get_user(opt, (int *)optval);
if (rc) if (rc)
goto out; goto out;
rc = -EINVAL; rc = -EINVAL;
llc_core = llc_sk(llc_ui->core_sk);
switch (optname) { switch (optname) {
case LLC_OPT_RETRY: case LLC_OPT_RETRY:
if (opt > LLC_OPT_MAX_RETRY) if (opt > LLC_OPT_MAX_RETRY)
goto out; goto out;
llc_core->n2 = opt; llc->n2 = opt;
break; break;
case LLC_OPT_SIZE: case LLC_OPT_SIZE:
if (opt > LLC_OPT_MAX_SIZE) if (opt > LLC_OPT_MAX_SIZE)
goto out; goto out;
llc_core->n1 = opt; llc->n1 = opt;
break; break;
case LLC_OPT_ACK_TMR_EXP: case LLC_OPT_ACK_TMR_EXP:
if (opt > LLC_OPT_MAX_ACK_TMR_EXP) if (opt > LLC_OPT_MAX_ACK_TMR_EXP)
goto out; goto out;
llc_core->ack_timer.expire = opt; llc->ack_timer.expire = opt;
break; break;
case LLC_OPT_P_TMR_EXP: case LLC_OPT_P_TMR_EXP:
if (opt > LLC_OPT_MAX_P_TMR_EXP) if (opt > LLC_OPT_MAX_P_TMR_EXP)
goto out; goto out;
llc_core->pf_cycle_timer.expire = opt; llc->pf_cycle_timer.expire = opt;
break; break;
case LLC_OPT_REJ_TMR_EXP: case LLC_OPT_REJ_TMR_EXP:
if (opt > LLC_OPT_MAX_REJ_TMR_EXP) if (opt > LLC_OPT_MAX_REJ_TMR_EXP)
goto out; goto out;
llc_core->rej_sent_timer.expire = opt; llc->rej_sent_timer.expire = opt;
break; break;
case LLC_OPT_BUSY_TMR_EXP: case LLC_OPT_BUSY_TMR_EXP:
if (opt > LLC_OPT_MAX_BUSY_TMR_EXP) if (opt > LLC_OPT_MAX_BUSY_TMR_EXP)
goto out; goto out;
llc_core->busy_state_timer.expire = opt; llc->busy_state_timer.expire = opt;
break; break;
case LLC_OPT_TX_WIN: case LLC_OPT_TX_WIN:
if (opt > LLC_OPT_MAX_WIN) if (opt > LLC_OPT_MAX_WIN)
goto out; goto out;
llc_core->k = opt; llc->k = opt;
break; break;
case LLC_OPT_RX_WIN: case LLC_OPT_RX_WIN:
if (opt > LLC_OPT_MAX_WIN) if (opt > LLC_OPT_MAX_WIN)
goto out; goto out;
llc_core->rw = opt; llc->rw = opt;
break; break;
default: default:
rc = -ENOPROTOOPT; rc = -ENOPROTOOPT;
...@@ -1246,40 +1128,35 @@ static int llc_ui_getsockopt(struct socket *sock, int level, int optname, ...@@ -1246,40 +1128,35 @@ static int llc_ui_getsockopt(struct socket *sock, int level, int optname,
char *optval, int *optlen) char *optval, int *optlen)
{ {
struct sock *sk = sock->sk; struct sock *sk = sock->sk;
struct llc_ui_opt *llc_ui = llc_ui_sk(sk); struct llc_opt *llc = llc_sk(sk);
struct llc_opt *llc_core;
int val = 0, len = 0, rc = -EINVAL; int val = 0, len = 0, rc = -EINVAL;
lock_sock(sk); lock_sock(sk);
if (level != SOL_LLC) if (level != SOL_LLC)
goto out; goto out;
rc = -ENOTCONN;
if (!llc_ui->core_sk)
goto out;
rc = get_user(len, optlen); rc = get_user(len, optlen);
if (rc) if (rc)
goto out; goto out;
rc = -EINVAL; rc = -EINVAL;
if (len != sizeof(int)) if (len != sizeof(int))
goto out; goto out;
llc_core = llc_sk(llc_ui->core_sk);
switch (optname) { switch (optname) {
case LLC_OPT_RETRY: case LLC_OPT_RETRY:
val = llc_core->n2; break; val = llc->n2; break;
case LLC_OPT_SIZE: case LLC_OPT_SIZE:
val = llc_core->n1; break; val = llc->n1; break;
case LLC_OPT_ACK_TMR_EXP: case LLC_OPT_ACK_TMR_EXP:
val = llc_core->ack_timer.expire; break; val = llc->ack_timer.expire; break;
case LLC_OPT_P_TMR_EXP: case LLC_OPT_P_TMR_EXP:
val = llc_core->pf_cycle_timer.expire; break; val = llc->pf_cycle_timer.expire; break;
case LLC_OPT_REJ_TMR_EXP: case LLC_OPT_REJ_TMR_EXP:
val = llc_core->rej_sent_timer.expire; break; val = llc->rej_sent_timer.expire; break;
case LLC_OPT_BUSY_TMR_EXP: case LLC_OPT_BUSY_TMR_EXP:
val = llc_core->busy_state_timer.expire; break; val = llc->busy_state_timer.expire; break;
case LLC_OPT_TX_WIN: case LLC_OPT_TX_WIN:
val = llc_core->k; break; val = llc->k; break;
case LLC_OPT_RX_WIN: case LLC_OPT_RX_WIN:
val = llc_core->rw; break; val = llc->rw; break;
default: default:
rc = -ENOPROTOOPT; rc = -ENOPROTOOPT;
goto out; goto out;
...@@ -1302,7 +1179,7 @@ static void llc_ui_ind_test(struct llc_prim_if_block *prim) ...@@ -1302,7 +1179,7 @@ static void llc_ui_ind_test(struct llc_prim_if_block *prim)
{ {
struct llc_prim_test *prim_data = &prim->data->test; struct llc_prim_test *prim_data = &prim->data->test;
struct sk_buff *skb = prim_data->skb; struct sk_buff *skb = prim_data->skb;
struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb); struct sockaddr_llc *addr = llc_ui_skb_cb(skb);
struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr, struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr,
&prim_data->saddr, skb->dev); &prim_data->saddr, skb->dev);
if (!sk) if (!sk)
...@@ -1310,15 +1187,15 @@ static void llc_ui_ind_test(struct llc_prim_if_block *prim) ...@@ -1310,15 +1187,15 @@ static void llc_ui_ind_test(struct llc_prim_if_block *prim)
if (sk->state == TCP_LISTEN) if (sk->state == TCP_LISTEN)
goto out_put; goto out_put;
/* save primitive for use by the user. */ /* save primitive for use by the user. */
llc_ui->sllc_family = AF_LLC; addr->sllc_family = AF_LLC;
llc_ui->sllc_arphrd = skb->dev->type; addr->sllc_arphrd = skb->dev->type;
llc_ui->sllc_test = 1; addr->sllc_test = 1;
llc_ui->sllc_xid = 0; addr->sllc_xid = 0;
llc_ui->sllc_ua = 0; addr->sllc_ua = 0;
llc_ui->sllc_dsap = prim_data->daddr.lsap; addr->sllc_dsap = prim_data->daddr.lsap;
memcpy(llc_ui->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN); memcpy(addr->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN);
llc_ui->sllc_ssap = prim_data->saddr.lsap; addr->sllc_ssap = prim_data->saddr.lsap;
memcpy(llc_ui->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN); memcpy(addr->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN);
/* queue skb to the user. */ /* queue skb to the user. */
if (sock_queue_rcv_skb(sk, skb)) if (sock_queue_rcv_skb(sk, skb))
kfree_skb(skb); kfree_skb(skb);
...@@ -1337,7 +1214,7 @@ static void llc_ui_ind_xid(struct llc_prim_if_block *prim) ...@@ -1337,7 +1214,7 @@ static void llc_ui_ind_xid(struct llc_prim_if_block *prim)
{ {
struct llc_prim_xid *prim_data = &prim->data->xid; struct llc_prim_xid *prim_data = &prim->data->xid;
struct sk_buff *skb = prim_data->skb; struct sk_buff *skb = prim_data->skb;
struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb); struct sockaddr_llc *addr = llc_ui_skb_cb(skb);
struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr, struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr,
&prim_data->saddr, skb->dev); &prim_data->saddr, skb->dev);
if (!sk) if (!sk)
...@@ -1345,15 +1222,15 @@ static void llc_ui_ind_xid(struct llc_prim_if_block *prim) ...@@ -1345,15 +1222,15 @@ static void llc_ui_ind_xid(struct llc_prim_if_block *prim)
if (sk->state == TCP_LISTEN) if (sk->state == TCP_LISTEN)
goto out_put; goto out_put;
/* save primitive for use by the user. */ /* save primitive for use by the user. */
llc_ui->sllc_family = AF_LLC; addr->sllc_family = AF_LLC;
llc_ui->sllc_arphrd = 0; addr->sllc_arphrd = 0;
llc_ui->sllc_test = 0; addr->sllc_test = 0;
llc_ui->sllc_xid = 1; addr->sllc_xid = 1;
llc_ui->sllc_ua = 0; addr->sllc_ua = 0;
llc_ui->sllc_dsap = prim_data->daddr.lsap; addr->sllc_dsap = prim_data->daddr.lsap;
memcpy(llc_ui->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN); memcpy(addr->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN);
llc_ui->sllc_ssap = prim_data->saddr.lsap; addr->sllc_ssap = prim_data->saddr.lsap;
memcpy(llc_ui->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN); memcpy(addr->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN);
/* queue skb to the user. */ /* queue skb to the user. */
if (sock_queue_rcv_skb(sk, skb)) if (sock_queue_rcv_skb(sk, skb))
kfree_skb(skb); kfree_skb(skb);
...@@ -1372,7 +1249,7 @@ static void llc_ui_ind_dataunit(struct llc_prim_if_block *prim) ...@@ -1372,7 +1249,7 @@ static void llc_ui_ind_dataunit(struct llc_prim_if_block *prim)
{ {
struct llc_prim_unit_data *prim_data = &prim->data->udata; struct llc_prim_unit_data *prim_data = &prim->data->udata;
struct sk_buff *skb = prim_data->skb; struct sk_buff *skb = prim_data->skb;
struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb); struct sockaddr_llc *addr = llc_ui_skb_cb(skb);
struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr, struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr,
&prim_data->saddr, skb->dev); &prim_data->saddr, skb->dev);
if (!sk) if (!sk)
...@@ -1380,88 +1257,15 @@ static void llc_ui_ind_dataunit(struct llc_prim_if_block *prim) ...@@ -1380,88 +1257,15 @@ static void llc_ui_ind_dataunit(struct llc_prim_if_block *prim)
if (sk->state == TCP_LISTEN) if (sk->state == TCP_LISTEN)
goto out_put; goto out_put;
/* save primitive for use by the user. */ /* save primitive for use by the user. */
llc_ui->sllc_family = AF_LLC; addr->sllc_family = AF_LLC;
llc_ui->sllc_arphrd = skb->dev->type; addr->sllc_arphrd = skb->dev->type;
llc_ui->sllc_test = 0; addr->sllc_test = 0;
llc_ui->sllc_xid = 0; addr->sllc_xid = 0;
llc_ui->sllc_ua = 1; addr->sllc_ua = 1;
llc_ui->sllc_dsap = prim_data->daddr.lsap; addr->sllc_dsap = prim_data->daddr.lsap;
memcpy(llc_ui->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN); memcpy(addr->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN);
llc_ui->sllc_ssap = prim_data->saddr.lsap; addr->sllc_ssap = prim_data->saddr.lsap;
memcpy(llc_ui->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN); memcpy(addr->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN);
/* queue skb to the user. */
if (sock_queue_rcv_skb(sk, skb))
kfree_skb(skb);
out_put:
sock_put(sk);
out:;
}
/**
* llc_ui_ind_conn - handle CONNECT indication
* @prim: Primitive block provided by the llc layer.
*
* handle CONNECT indication.
*/
static void llc_ui_ind_conn(struct llc_prim_if_block *prim)
{
struct llc_prim_conn *prim_data = &prim->data->conn;
struct sock* sk;
struct sk_buff *skb2;
llc_sk(prim_data->sk)->laddr.lsap = prim->sap->laddr.lsap;
sk = llc_ui_find_sk_by_addr(&llc_sk(prim_data->sk)->laddr,
&prim_data->saddr, prim_data->dev);
if (!sk)
goto out;
if (sk->type != SOCK_STREAM || sk->state != TCP_LISTEN)
goto out_put;
if (prim->data->conn.status)
goto out_put; /* bad status. */
/* give this connection a link number. */
llc_sk(prim_data->sk)->link =
llc_ui_next_link_no(llc_sk(prim_data->sk)->laddr.lsap);
skb2 = alloc_skb(0, GFP_ATOMIC);
if (!skb2)
goto out_put;
skb2->sk = prim_data->sk;
skb_queue_tail(&sk->receive_queue, skb2);
sk->state_change(sk);
out_put:
sock_put(sk);
out:;
}
/**
* llc_ui_ind_data - handle DATA indication
* @prim: Primitive block provided by the llc layer.
*
* handle CONNECT indication.
*/
static void llc_ui_ind_data(struct llc_prim_if_block *prim)
{
struct llc_prim_data *prim_data = &prim->data->data;
struct sk_buff *skb = prim_data->skb;
struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb);
struct sock* sk = llc_sk(prim_data->sk)->handler;
if (!sk)
goto out;
sock_hold(sk);
if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED)
goto out_put;
/* save primitive for use by the user. */
llc_ui->sllc_family = AF_LLC;
llc_ui->sllc_arphrd = skb->dev->type;
llc_ui->sllc_test = 0;
llc_ui->sllc_xid = 0;
llc_ui->sllc_ua = 0;
llc_ui->sllc_dsap = llc_ui_sk(sk)->sap->laddr.lsap;
memcpy(llc_ui->sllc_dmac, llc_sk(prim_data->sk)->laddr.mac,
IFHWADDRLEN);
llc_ui->sllc_ssap = llc_sk(prim_data->sk)->daddr.lsap;
memcpy(llc_ui->sllc_smac, llc_sk(prim_data->sk)->daddr.mac,
IFHWADDRLEN);
/* queue skb to the user. */ /* queue skb to the user. */
if (sock_queue_rcv_skb(sk, skb)) if (sock_queue_rcv_skb(sk, skb))
kfree_skb(skb); kfree_skb(skb);
...@@ -1470,35 +1274,6 @@ static void llc_ui_ind_data(struct llc_prim_if_block *prim) ...@@ -1470,35 +1274,6 @@ static void llc_ui_ind_data(struct llc_prim_if_block *prim)
out:; out:;
} }
/**
* llc_ui_ind_disc - handle DISC indication
* @prim: Primitive block provided by the llc layer.
*
* handle DISC indication.
*/
static void llc_ui_ind_disc(struct llc_prim_if_block *prim)
{
struct llc_prim_disc *prim_data = &prim->data->disc;
struct sock* sk = llc_sk(prim_data->sk)->handler;
if (!sk)
goto out;
sock_hold(sk);
if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED)
goto out_put;
llc_ui_sk(sk)->core_sk = NULL;
sk->shutdown = SHUTDOWN_MASK;
sk->socket->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE;
if (!sk->dead) {
sk->state_change(sk);
sk->dead = 1;
}
out_put:
sock_put(sk);
out:;
}
/** /**
* llc_ui_indicate - LLC user interface hook into the LLC layer. * llc_ui_indicate - LLC user interface hook into the LLC layer.
* @prim: Primitive block provided by the llc layer. * @prim: Primitive block provided by the llc layer.
...@@ -1517,91 +1292,23 @@ static int llc_ui_indicate(struct llc_prim_if_block *prim) ...@@ -1517,91 +1292,23 @@ static int llc_ui_indicate(struct llc_prim_if_block *prim)
case LLC_DATAUNIT_PRIM: case LLC_DATAUNIT_PRIM:
llc_ui_ind_dataunit(prim); break; llc_ui_ind_dataunit(prim); break;
case LLC_CONN_PRIM: case LLC_CONN_PRIM:
llc_ui_ind_conn(prim); break; dprintk("%s: shouldn't happen, LLC_CONN_PRIM "
"is gone for ->ind()...\n", __FUNCTION__);
break;
case LLC_DATA_PRIM: case LLC_DATA_PRIM:
llc_ui_ind_data(prim); break; dprintk("%s: shouldn't happen, LLC_DATA_PRIM "
"is gone for ->ind()...\n", __FUNCTION__);
break;
case LLC_DISC_PRIM: case LLC_DISC_PRIM:
llc_ui_ind_disc(prim); break; dprintk("%s: shouldn't happen, LLC_DISC_PRIM "
"is gone for ->ind()...\n", __FUNCTION__);
break;
case LLC_RESET_PRIM: case LLC_RESET_PRIM:
case LLC_FLOWCONTROL_PRIM:
default: break; default: break;
} }
return 0; return 0;
} }
/**
* llc_ui_conf_conn - handle CONN confirm.
* @prim: Primitive block provided by the llc layer.
*
* handle CONN confirm.
*/
static void llc_ui_conf_conn(struct llc_prim_if_block *prim)
{
struct llc_prim_conn *prim_data = &prim->data->conn;
struct llc_opt *llc_core = llc_sk(prim_data->sk);
struct sock* sk = llc_core->handler;
struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
if (!sk)
goto out;
sock_hold(sk);
if (sk->type != SOCK_STREAM || sk->state != TCP_SYN_SENT)
goto out_put;
if (!prim->data->conn.status) {
sk->socket->state = SS_CONNECTED;
sk->state = TCP_ESTABLISHED;
llc_ui->core_sk = prim_data->sk;
} else {
sk->socket->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE;
llc_ui->core_sk = NULL;
}
sk->state_change(sk);
out_put:
sock_put(sk);
out:;
}
/**
* llc_ui_conf_data - handle DATA confirm.
* @prim: Primitive block provided by the llc layer.
*
* handle DATA confirm.
*/
static void llc_ui_conf_data(struct llc_prim_if_block *prim)
{
struct llc_prim_data *prim_data = &prim->data->data;
struct sock* sk = llc_sk(prim_data->sk)->handler;
if (sk)
wake_up(sk->sleep);
}
/**
* llc_ui_conf_disc - handle DISC confirm.
* @prim: Primitive block provided by the llc layer.
*
* handle DISC confirm.
*/
static void llc_ui_conf_disc(struct llc_prim_if_block *prim)
{
struct llc_prim_disc *prim_data = &prim->data->disc;
struct sock* sk = llc_sk(prim_data->sk)->handler;
if (!sk)
goto out;
sock_hold(sk);
if (sk->type != SOCK_STREAM || sk->state != TCP_CLOSING)
goto out_put;
llc_ui_sk(sk)->core_sk = NULL;
sk->socket->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE;
sk->state_change(sk);
out_put:
sock_put(sk);
out:;
}
/** /**
* llc_ui_confirm - LLC user interface hook into the LLC layer * llc_ui_confirm - LLC user interface hook into the LLC layer
* @prim: Primitive block provided by the llc layer. * @prim: Primitive block provided by the llc layer.
...@@ -1614,14 +1321,20 @@ static int llc_ui_confirm(struct llc_prim_if_block *prim) ...@@ -1614,14 +1321,20 @@ static int llc_ui_confirm(struct llc_prim_if_block *prim)
{ {
switch (prim->prim) { switch (prim->prim) {
case LLC_CONN_PRIM: case LLC_CONN_PRIM:
llc_ui_conf_conn(prim); break; dprintk("%s: shouldn't happen, LLC_CONN_PRIM "
"is gone for ->conf()...\n", __FUNCTION__);
break;
case LLC_DATA_PRIM: case LLC_DATA_PRIM:
llc_ui_conf_data(prim); break; dprintk("%s: shouldn't happen, LLC_DATA_PRIM "
"is gone for ->conf()...\n", __FUNCTION__);
break;
case LLC_DISC_PRIM: case LLC_DISC_PRIM:
llc_ui_conf_disc(prim); break; dprintk("%s: shouldn't happen, LLC_DISC_PRIM "
"is gone for ->conf()...\n", __FUNCTION__);
break;
case LLC_RESET_PRIM: break; case LLC_RESET_PRIM: break;
default: default:
printk(KERN_ERR "%s: unknown prim %d\n", __FUNCTION__, printk(KERN_ERR "%s: prim not supported%d\n", __FUNCTION__,
prim->prim); prim->prim);
break; break;
} }
...@@ -1651,46 +1364,42 @@ static int llc_ui_get_info(char *buffer, char **start, off_t offset, int length) ...@@ -1651,46 +1364,42 @@ static int llc_ui_get_info(char *buffer, char **start, off_t offset, int length)
off_t pos = 0; off_t pos = 0;
off_t begin = 0; off_t begin = 0;
struct sock *s; struct sock *s;
int len = sprintf(buffer, "SocketID SKt Mc local_mac_sap\t " int len = sprintf(buffer, "SKt Mc local_mac_sap "
"remote_mac_sap\t tx_queue rx_queue st uid " "remote_mac_sap tx_queue rx_queue st uid "
"link_no\n"); "link\n");
/* Output the LLC socket data for the /proc filesystem */ /* Output the LLC socket data for the /proc filesystem */
read_lock_bh(&llc_ui_sockets_lock); read_lock_bh(&llc_ui_sockets_lock);
for (s = llc_ui_sockets; s; s = s->next) { for (s = llc_ui_sockets; s; s = s->next) {
struct llc_ui_opt *llc_ui = llc_ui_sk(s); struct llc_opt *llc = llc_sk(s);
len += sprintf(buffer + len, "%p %02X %02X ", s, s->type,
!llc_ui_mac_null(llc_ui->addr.sllc_mmac)); len += sprintf(buffer + len, "%2X %2X ", s->type,
if (llc_ui->sap) { !llc_mac_null(llc->addr.sllc_mmac));
if (llc_ui->dev && if (llc->sap) {
llc_ui_mac_null(llc_ui->addr.sllc_mmac)) if (llc->dev && llc_mac_null(llc->addr.sllc_mmac))
llc_ui_format_mac(buffer + len, llc_ui_format_mac(buffer + len,
llc_ui->dev->dev_addr); llc->dev->dev_addr);
else { else {
if (!llc_ui_mac_null(llc_ui->addr.sllc_mmac)) if (!llc_mac_null(llc->addr.sllc_mmac))
llc_ui_format_mac(buffer + len, llc_ui_format_mac(buffer + len,
llc_ui->addr.sllc_mmac); llc->addr.sllc_mmac);
else else
sprintf(buffer + len, sprintf(buffer + len,
"00:00:00:00:00:00"); "00:00:00:00:00:00");
} }
len += MAC_FORMATTED_SIZE; len += MAC_FORMATTED_SIZE;
len += sprintf(buffer + len, "@%02X ", len += sprintf(buffer + len, "@%02X ",
llc_ui->sap->laddr.lsap); llc->sap->laddr.lsap);
} else } else
len += sprintf(buffer + len, "00:00:00:00:00:00@00 "); len += sprintf(buffer + len, "00:00:00:00:00:00@00 ");
llc_ui_format_mac(buffer + len, llc_ui->addr.sllc_dmac); llc_ui_format_mac(buffer + len, llc->addr.sllc_dmac);
len += MAC_FORMATTED_SIZE; len += MAC_FORMATTED_SIZE;
len += sprintf(buffer + len, len += sprintf(buffer + len,
"@%02X %08d:%08d %02d %-3d ", "@%02X %8d %8d %2d %-3d ",
llc_ui->addr.sllc_dsap, llc->addr.sllc_dsap,
atomic_read(&s->wmem_alloc), atomic_read(&s->wmem_alloc),
atomic_read(&s->rmem_alloc), s->state, atomic_read(&s->rmem_alloc), s->state,
SOCK_INODE(s->socket)->i_uid); SOCK_INODE(s->socket)->i_uid);
if (llc_ui->core_sk) len += sprintf(buffer + len, "%-4d\n", llc->link);
len += sprintf(buffer + len, "%-7d\n",
llc_sk(llc_ui->core_sk)->link);
else
len += sprintf(buffer + len, "no_link\n");
/* Are we still dumping unwanted data then discard the record */ /* Are we still dumping unwanted data then discard the record */
pos = begin + len; pos = begin + len;
...@@ -1741,7 +1450,7 @@ static struct proto_ops SOCKOPS_WRAPPED(llc_ui_ops) = { ...@@ -1741,7 +1450,7 @@ static struct proto_ops SOCKOPS_WRAPPED(llc_ui_ops) = {
SOCKOPS_WRAP(llc_ui, PF_LLC); SOCKOPS_WRAP(llc_ui, PF_LLC);
static char llc_ui_banner[] __initdata = static char llc_ui_banner[] __initdata =
KERN_INFO "NET4.0 IEEE 802.2 User Interface SAPs, Jay Schulist, 2001\n"; KERN_INFO "NET4.0 IEEE 802.2 BSD sockets, Jay Schulist, 2001, Arnaldo C. Melo, 2002\n";
int __init llc_ui_init(void) int __init llc_ui_init(void)
{ {
......
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