Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
ed54ae2e
Commit
ed54ae2e
authored
Sep 13, 2002
by
David S. Miller
Browse files
Options
Browse Files
Download
Plain Diff
Merge master.kernel.org:/home/acme/BK/llc-2.5
into nuts.ninka.net:/home/davem/src/BK/llc-2.5
parents
c39f7320
96b2cae7
Changes
19
Show whitespace changes
Inline
Side-by-side
Showing
19 changed files
with
1028 additions
and
1479 deletions
+1028
-1479
include/linux/llc.h
include/linux/llc.h
+0
-11
include/net/llc_c_st.h
include/net/llc_c_st.h
+6
-6
include/net/llc_conn.h
include/net/llc_conn.h
+13
-60
include/net/llc_if.h
include/net/llc_if.h
+29
-39
include/net/llc_mac.h
include/net/llc_mac.h
+36
-5
include/net/llc_main.h
include/net/llc_main.h
+2
-2
include/net/llc_pdu.h
include/net/llc_pdu.h
+28
-28
include/net/llc_sap.h
include/net/llc_sap.h
+1
-4
net/llc/llc_actn.c
net/llc/llc_actn.c
+2
-2
net/llc/llc_c_ac.c
net/llc/llc_c_ac.c
+60
-93
net/llc/llc_c_ev.c
net/llc/llc_c_ev.c
+8
-12
net/llc/llc_conn.c
net/llc/llc_conn.c
+160
-56
net/llc/llc_if.c
net/llc/llc_if.c
+136
-305
net/llc/llc_mac.c
net/llc/llc_mac.c
+93
-76
net/llc/llc_main.c
net/llc/llc_main.c
+54
-31
net/llc/llc_pdu.c
net/llc/llc_pdu.c
+49
-81
net/llc/llc_s_ac.c
net/llc/llc_s_ac.c
+5
-18
net/llc/llc_sap.c
net/llc/llc_sap.c
+10
-23
net/llc/llc_sock.c
net/llc/llc_sock.c
+336
-627
No files found.
include/linux/llc.h
View file @
ed54ae2e
...
...
@@ -78,17 +78,6 @@ enum llc_sockopts {
#define LLC_SAP_DYN_STOP 0xDE
#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]))
#ifdef CONFIG_LLC_UI
...
...
include/net/llc_c_st.h
View file @
ed54ae2e
include/net/llc_conn.h
View file @
ed54ae2e
...
...
@@ -2,7 +2,7 @@
#define LLC_CONN_H
/*
* 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
* GNU General Public License as published by the Free Software Foundation.
...
...
@@ -13,8 +13,7 @@
*/
#include <linux/timer.h>
#include <net/llc_if.h>
#undef DEBUG_LLC_CONN_ALLOC
#include <linux/llc.h>
struct
llc_timer
{
struct
timer_list
timer
;
...
...
@@ -25,7 +24,7 @@ struct llc_timer {
struct
llc_opt
{
struct
list_head
node
;
/* entry in sap->sk_list.list */
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 */
struct
llc_sap
*
sap
;
/* pointer to parent SAP */
struct
llc_addr
laddr
;
/* lsap/mac pair */
...
...
@@ -80,63 +79,14 @@ struct llc_opt {
struct
llc_conn_state_ev
;
extern
struct
sock
*
__llc_sock_alloc
(
void
);
extern
void
__llc_sock_free
(
struct
sock
*
sk
,
u8
free
);
#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
struct
sock
*
llc_sk_alloc
(
int
family
,
int
priority
);
extern
void
llc_sk_free
(
struct
sock
*
sk
);
extern
void
llc_s
oc
k_reset
(
struct
sock
*
sk
);
extern
int
llc_s
oc
k_init
(
struct
sock
*
sk
);
extern
void
llc_sk_reset
(
struct
sock
*
sk
);
extern
int
llc_sk_init
(
struct
sock
*
sk
);
/* Access to a connection */
extern
int
llc_conn_s
end_ev
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
);
extern
int
llc_conn_s
tate_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_rtn_pdu
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
);
extern
void
llc_conn_free_ev
(
struct
sk_buff
*
skb
);
...
...
@@ -146,7 +96,10 @@ extern void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr,
u8
first_f_bit
);
extern
int
llc_conn_remove_acked_pdus
(
struct
sock
*
conn
,
u8
nr
,
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
*
daddr
,
struct
llc_addr
*
laddr
);
extern
struct
sock
*
llc_lookup_listener
(
struct
llc_sap
*
sap
,
struct
llc_addr
*
laddr
);
extern
u8
llc_data_accept_state
(
u8
state
);
extern
void
llc_build_offset_table
(
void
);
...
...
include/net/llc_if.h
View file @
ed54ae2e
...
...
@@ -14,13 +14,15 @@
/* Defines LLC interface to network layer */
/* Available primitives */
#include <linux/if.h>
#include <linux/if_arp.h>
#include <linux/llc.h>
#define LLC_DATAUNIT_PRIM 0
#define LLC_CONN_PRIM 1
#define LLC_DATA_PRIM 2
#define LLC_DISC_PRIM 3
#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_XID_PRIM 7
#define LLC_TEST_PRIM 8
...
...
@@ -65,46 +67,12 @@ struct llc_addr {
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
sock
*
sk
;
u16
link
;
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 */
struct
llc_prim_unit_data
{
struct
llc_addr
saddr
;
...
...
@@ -129,11 +97,7 @@ struct llc_prim_test {
};
union
llc_u_prim_data
{
struct
llc_prim_conn
conn
;
struct
llc_prim_disc
disc
;
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_xid
xid
;
struct
llc_prim_test
test
;
...
...
@@ -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
,
llc_prim_call_t
network_confirm
,
u8
lsap
);
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 */
include/net/llc_mac.h
View file @
ed54ae2e
...
...
@@ -2,7 +2,7 @@
#define LLC_MAC_H
/*
* 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
* GNU General Public License as published by the Free Software Foundation.
...
...
@@ -13,13 +13,12 @@
*/
/* Defines MAC-layer interface to LLC layer */
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
);
extern
struct
net_device
*
mac_dev_peer
(
struct
net_device
*
current_dev
,
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
int
llc_conn_rcv
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
);
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)
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 */
include/net/llc_main.h
View file @
ed54ae2e
...
...
@@ -61,7 +61,7 @@ extern void llc_sap_save(struct llc_sap *sap);
extern
void
llc_free_sap
(
struct
llc_sap
*
sap
);
extern
struct
llc_sap
*
llc_sap_find
(
u8
lsap
);
extern
struct
llc_station
*
llc_station_get
(
void
);
extern
void
llc_station_s
end_ev
(
struct
llc_station
*
station
,
extern
void
llc_station_s
tate_process
(
struct
llc_station
*
station
,
struct
sk_buff
*
skb
);
extern
void
llc_station_send_pdu
(
struct
llc_station
*
station
,
struct
sk_buff
*
skb
);
...
...
include/net/llc_pdu.h
View file @
ed54ae2e
...
...
@@ -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_pf_bit
(
struct
sk_buff
*
skb
,
u8
bit_value
);
extern
int
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
int
llc_pdu_decode_sa
(
struct
sk_buff
*
skb
,
u8
*
sa
);
extern
int
llc_pdu_decode_da
(
struct
sk_buff
*
skb
,
u8
*
ds
);
extern
int
llc_pdu_decode_dsap
(
struct
sk_buff
*
skb
,
u8
*
dsap
);
extern
int
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_pdu_decode_pf_bit
(
struct
sk_buff
*
skb
,
u8
*
pf_bit
);
extern
void
llc_pdu_decode_cr_bit
(
struct
sk_buff
*
skb
,
u8
*
cr_bit
);
extern
void
llc_pdu_decode_sa
(
struct
sk_buff
*
skb
,
u8
*
sa
);
extern
void
llc_pdu_decode_da
(
struct
sk_buff
*
skb
,
u8
*
ds
);
extern
void
llc_pdu_decode_dsap
(
struct
sk_buff
*
skb
,
u8
*
dsap
);
extern
void
llc_pdu_decode_ssap
(
struct
sk_buff
*
skb
,
u8
*
ssap
);
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
,
u8
dsap
,
u8
cr
);
extern
int
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_ui_cmd
(
struct
sk_buff
*
skb
);
extern
void
llc_pdu_init_as_xid_cmd
(
struct
sk_buff
*
skb
,
u8
svcs_supported
,
u8
rx_window
);
extern
int
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
int
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
int
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
int
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
int
llc_pdu_init_as_xid_rsp
(
struct
sk_buff
*
skb
,
u8
svcs_supported
,
extern
void
llc_pdu_init_as_test_cmd
(
struct
sk_buff
*
skb
);
extern
void
llc_pdu_init_as_disc_cmd
(
struct
sk_buff
*
skb
,
u8
p_bit
);
extern
void
llc_pdu_init_as_i_cmd
(
struct
sk_buff
*
skb
,
u8
p_bit
,
u8
ns
,
u8
nr
);
extern
void
llc_pdu_init_as_rej_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
void
llc_pdu_init_as_rr_cmd
(
struct
sk_buff
*
skb
,
u8
p_bit
,
u8
nr
);
extern
void
llc_pdu_init_as_sabme_cmd
(
struct
sk_buff
*
skb
,
u8
p_bit
);
extern
void
llc_pdu_init_as_dm_rsp
(
struct
sk_buff
*
skb
,
u8
f_bit
);
extern
void
llc_pdu_init_as_xid_rsp
(
struct
sk_buff
*
skb
,
u8
svcs_supported
,
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
);
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
,
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
int
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
int
llc_pdu_init_as_ua_rsp
(
struct
sk_buff
*
skb
,
u8
f_bit
);
extern
void
llc_pdu_init_as_rr_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
void
llc_pdu_init_as_rnr_rsp
(
struct
sk_buff
*
skb
,
u8
f_bit
,
u8
nr
);
extern
void
llc_pdu_init_as_ua_rsp
(
struct
sk_buff
*
skb
,
u8
f_bit
);
#endif
/* LLC_PDU_H */
include/net/llc_sap.h
View file @
ed54ae2e
...
...
@@ -18,7 +18,6 @@
* @p_bit - only lowest-order bit used
* @f_bit - only lowest-order bit used
* @req - provided by LLC layer
* @resp - provided by LLC layer
* @ind - provided by network layer
* @conf - provided by network layer
* @laddr - SAP value in this 'lsap'
...
...
@@ -31,8 +30,6 @@ struct llc_sap {
u8
state
;
u8
p_bit
;
u8
f_bit
;
llc_prim_call_t
req
;
llc_prim_call_t
resp
;
llc_prim_call_t
ind
;
llc_prim_call_t
conf
;
struct
llc_prim_if_block
llc_ind_prim
,
llc_cfm_prim
;
...
...
@@ -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_unassign_sock
(
struct
llc_sap
*
sap
,
struct
sock
*
sk
);
extern
void
llc_sap_s
end_ev
(
struct
llc_sap
*
sap
,
struct
sk_buff
*
skb
);
extern
void
llc_sap_s
tate_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_send_pdu
(
struct
llc_sap
*
sap
,
struct
sk_buff
*
skb
);
#endif
/* LLC_SAP_H */
net/llc/llc_actn.c
View file @
ed54ae2e
...
...
@@ -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
)
{
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
;
if
(
skb
)
{
...
...
@@ -142,6 +142,6 @@ static void llc_station_ack_tmr_callback(unsigned long timeout_data)
ev
->
type
=
LLC_STATION_EV_TYPE_ACK_TMR
;
ev
->
data
.
tmr
.
timer_specific
=
NULL
;
llc_station_s
end_ev
(
station
,
skb
);
llc_station_s
tate_process
(
station
,
skb
);
}
}
net/llc/llc_c_ac.c
View file @
ed54ae2e
...
...
@@ -65,24 +65,14 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb)
sap
=
llc_sap_find
(
dsap
);
if
(
sap
)
{
struct
llc_conn_state_ev
*
ev
=
llc_conn_ev
(
skb
);
struct
llc_prim_if_block
*
prim
=
&
sap
->
llc_ind_prim
;
union
llc_u_prim_data
*
prim_data
=
prim
->
data
;
struct
llc_opt
*
llc
=
llc_sk
(
sk
);
prim_data
->
conn
.
daddr
.
lsap
=
dsap
;
llc_pdu_decode_sa
(
skb
,
llc
->
daddr
.
mac
);
llc_pdu_decode_da
(
skb
,
llc
->
laddr
.
mac
);
llc
->
dev
=
skb
->
dev
;
prim_data
->
conn
.
pri
=
0
;
prim_data
->
conn
.
sk
=
sk
;
prim_data
->
conn
.
dev
=
skb
->
dev
;
memcpy
(
&
prim_data
->
conn
.
daddr
,
&
llc
->
laddr
,
sizeof
(
llc
->
laddr
));
memcpy
(
&
prim_data
->
conn
.
saddr
,
&
llc
->
daddr
,
sizeof
(
llc
->
daddr
));
prim
->
data
=
prim_data
;
prim
->
prim
=
LLC_CONN_PRIM
;
prim
->
sap
=
llc
->
sap
;
ev
->
flag
=
1
;
ev
->
ind_prim
=
prim
;
/* FIXME: find better way to notify upper layer */
ev
->
flag
=
LLC_CONN_PRIM
+
1
;
ev
->
ind_prim
=
(
void
*
)
1
;
rc
=
0
;
}
return
rc
;
...
...
@@ -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
)
{
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
;
prim_data
->
conn
.
pri
=
0
;
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
;
ev
->
flag
=
LLC_CONN_PRIM
+
1
;
ev
->
cfm_prim
=
(
void
*
)
1
;
return
0
;
}
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_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
;
prim_data
->
data
.
link
=
llc
->
link
;
prim_data
->
data
.
status
=
LLC_STATUS_RECEIVED
;
prim_data
->
data
.
skb
=
NULL
;
prim
->
data
=
prim_data
;
prim
->
prim
=
LLC_DATA_PRIM
;
prim
->
sap
=
sap
;
ev
->
flag
=
1
;
ev
->
cfm_prim
=
prim
;
/*
* FIXME: find better way to tell upper layer that the packet was
* confirmed by the other endpoint
*/
ev
->
flag
=
LLC_DATA_PRIM
+
1
;
ev
->
cfm_prim
=
(
void
*
)
1
;
return
0
;
}
...
...
@@ -164,19 +134,15 @@ int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb)
rc
=
1
;
}
if
(
!
rc
)
{
struct
llc_opt
*
llc
=
llc_sk
(
sk
);
struct
llc_sap
*
sap
=
llc
->
sap
;
struct
llc_prim_if_block
*
prim
=
&
sap
->
llc_ind_prim
;
union
llc_u_prim_data
*
prim_data
=
prim
->
data
;
prim_data
->
disc
.
sk
=
sk
;
prim_data
->
disc
.
reason
=
reason
;
prim_data
->
disc
.
link
=
llc
->
link
;
prim
->
data
=
prim_data
;
prim
->
prim
=
LLC_DISC_PRIM
;
prim
->
sap
=
llc
->
sap
;
ev
->
flag
=
1
;
ev
->
ind_prim
=
prim
;
/*
* FIXME: ev needs reason field,
* perhaps the ev->status is enough,
* have to check,
* better way to signal its a disc
*/
/* prim_data->disc.reason = reason; */
ev
->
flag
=
LLC_DISC_PRIM
+
1
;
ev
->
ind_prim
=
(
void
*
)
1
;
}
return
rc
;
}
...
...
@@ -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
)
{
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
;
prim_data
->
disc
.
reason
=
ev
->
status
;
prim_data
->
disc
.
link
=
llc
->
link
;
prim
->
data
=
prim_data
;
prim
->
prim
=
LLC_DISC_PRIM
;
prim
->
sap
=
sap
;
ev
->
flag
=
1
;
ev
->
cfm_prim
=
prim
;
/* here we use the ev->status, humm */
/* prim_data->disc.reason = ev->status; */
ev
->
flag
=
LLC_DISC_PRIM
+
1
;
ev
->
cfm_prim
=
(
void
*
)
1
;
return
0
;
}
...
...
@@ -1342,13 +1300,16 @@ 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
)
{
struct
llc_pdu_sn
*
pdu
=
llc_pdu_sn_hdr
(
skb
);
if
(
!
LLC_PDU_IS_RSP
(
pdu
))
{
u8
f_bit
;
if
(
!
LLC_PDU_IS_RSP
(
pdu
)
&&
!
llc_pdu_decode_pf_bit
(
skb
,
&
f_bit
)
&&
f_bit
)
{
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
;
}
...
...
@@ -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
)
{
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
;
if
(
skb
)
{
struct
llc_conn_state_ev
*
ev
=
llc_conn_ev
(
skb
);
skb
->
sk
=
sk
;
ev
->
type
=
LLC_CONN_EV_TYPE_P_TMR
;
ev
->
data
.
tmr
.
timer_specific
=
NULL
;
llc_process_tmr_ev
(
sk
,
skb
);
}
bh_unlock_sock
(
sk
);
}
static
void
llc_conn_busy_tmr_cb
(
unsigned
long
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
;
if
(
skb
)
{
struct
llc_conn_state_ev
*
ev
=
llc_conn_ev
(
skb
);
skb
->
sk
=
sk
;
ev
->
type
=
LLC_CONN_EV_TYPE_BUSY_TMR
;
ev
->
data
.
tmr
.
timer_specific
=
NULL
;
llc_process_tmr_ev
(
sk
,
skb
);
}
bh_unlock_sock
(
sk
);
}
void
llc_conn_ack_tmr_cb
(
unsigned
long
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
;
if
(
skb
)
{
struct
llc_conn_state_ev
*
ev
=
llc_conn_ev
(
skb
);
skb
->
sk
=
sk
;
ev
->
type
=
LLC_CONN_EV_TYPE_ACK_TMR
;
ev
->
data
.
tmr
.
timer_specific
=
NULL
;
llc_process_tmr_ev
(
sk
,
skb
);
}
bh_unlock_sock
(
sk
);
}
static
void
llc_conn_rej_tmr_cb
(
unsigned
long
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
;
if
(
skb
)
{
struct
llc_conn_state_ev
*
ev
=
llc_conn_ev
(
skb
);
skb
->
sk
=
sk
;
ev
->
type
=
LLC_CONN_EV_TYPE_REJ_TMR
;
ev
->
data
.
tmr
.
timer_specific
=
NULL
;
llc_process_tmr_ev
(
sk
,
skb
);
}
bh_unlock_sock
(
sk
);
}
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)
* llc_conn_disc - removes connection from SAP list and frees it
* @sk: closed connection
* @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
)
{
llc_sap_unassign_sock
(
llc_sk
(
sk
)
->
sap
,
sk
);
llc_sock_free
(
sk
);
return
2
;
/* FIXME: this thing seems to want to die */
return
0
;
}
/**
...
...
@@ -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
)
{
llc_s
oc
k_reset
(
sk
);
llc_sk_reset
(
sk
);
return
0
;
}
...
...
@@ -1589,24 +1559,21 @@ u8 llc_circular_between(u8 a, u8 b, u8 c)
* This function is called from timer callback functions. When connection
* is busy (during sending a data frame) timer expiration event must be
* queued. Otherwise this event can be sent to connection state machine.
* Queued events will process by
process_rxframes_events function after
*
sending data frame. Returns 0 for success, 1 otherwis
e.
* Queued events will process by
llc_backlog_rcv function after sending
*
data fram
e.
*/
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
)
{
printk
(
KERN_WARNING
"%s: timer called on closed connection
\n
"
,
__FUNCTION__
);
llc_conn_free_ev
(
skb
);
goto
out
;
}
}
else
{
if
(
!
sk
->
lock
.
users
)
llc_conn_send_ev
(
sk
,
skb
);
llc_conn_state_process
(
sk
,
skb
);
else
{
llc_set_backlog_type
(
skb
,
LLC_EVENT
);
sk_add_backlog
(
sk
,
skb
);
}
out:
bh_unlock_sock
(
sk
);
}
}
net/llc/llc_c_ev.c
View file @
ed54ae2e
...
...
@@ -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
&&
llc_util_ns_inside_rx_window
(
ns
,
vr
,
llc_sk
(
sk
)
->
rw
)
?
0
:
1
;
if
(
!
rc
)
dprintk
(
KERN_WARNING
"rx_i_cmd_p_bit_set_x_inval_ns matched,"
"state = %d, ns = %d, vr = %d
\n
"
,
llc_sk
(
sk
)
->
state
,
ns
,
vr
);
dprintk
(
"%s: matched, state=%d, ns=%d, vr=%d
\n
"
,
__FUNCTION__
,
llc_sk
(
sk
)
->
state
,
ns
,
vr
);
return
rc
;
}
...
...
@@ -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
&&
llc_util_ns_inside_rx_window
(
ns
,
vr
,
llc_sk
(
sk
)
->
rw
)
?
0
:
1
;
if
(
!
rc
)
dprintk
(
KERN_WARNING
"conn_ev_rx_i_rsp_fbit_set_x_inval_ns "
"matched : state = %d, ns = %d, vr = %d
\n
"
,
llc_sk
(
sk
)
->
state
,
ns
,
vr
);
dprintk
(
"%s: matched, state=%d, ns=%d, vr=%d
\n
"
,
__FUNCTION__
,
llc_sk
(
sk
)
->
state
,
ns
,
vr
);
return
rc
;
}
...
...
@@ -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
)
&&
(
!
LLC_PDU_TYPE_IS_I
(
pdu
)
||
!
LLC_PDU_TYPE_IS_S
(
pdu
))
&&
nr
!=
vs
&&
llc_util_nr_inside_tx_window
(
sk
,
nr
))
{
dprintk
(
KERN_ERR
"conn_ev_rx_zzz_cmd_inv_nr matched, state = "
"%d, vs = %d, nr = %d
\n
"
,
llc_sk
(
sk
)
->
state
,
vs
,
nr
);
dprintk
(
"%s: matched, state=%d, vs=%d, nr=%d
\n
"
,
__FUNCTION__
,
llc_sk
(
sk
)
->
state
,
vs
,
nr
);
rc
=
0
;
}
return
rc
;
...
...
@@ -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
))
&&
nr
!=
vs
&&
llc_util_nr_inside_tx_window
(
sk
,
nr
))
{
rc
=
0
;
dprintk
(
KERN_ERR
"conn_ev_rx_zzz_fbit_set_x_inval_nr matched, "
"state = %d, vs = %d, nr = %d
\n
"
,
llc_sk
(
sk
)
->
state
,
vs
,
nr
);
dprintk
(
"%s: matched, state=%d, vs=%d, nr=%d
\n
"
,
__FUNCTION__
,
llc_sk
(
sk
)
->
state
,
vs
,
nr
);
}
return
rc
;
}
...
...
net/llc/llc_conn.c
View file @
ed54ae2e
...
...
@@ -18,6 +18,7 @@
#include <net/llc_sap.h>
#include <net/llc_conn.h>
#include <net/sock.h>
#include <linux/tcp.h>
#include <net/llc_main.h>
#include <net/llc_c_ev.h>
#include <net/llc_c_ac.h>
...
...
@@ -38,65 +39,149 @@ static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk,
/* Offset table on connection states transition diagram */
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_s
end_event
- sends event to connection state machine
* llc_conn_s
tate_process
- sends event to connection state machine
* @sk: connection
* @skb: occurred event
*
* Sends an event to connection state machine.
a
fter processing event
* Sends an event to connection state machine.
A
fter processing event
* (executing it's actions and changing state), upper layer will be
* indicated or confirmed, if needed. Returns 0 for success, 1 for
* failure. The socket lock has to be held before calling this function.
*/
int
llc_conn_s
end_ev
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
int
llc_conn_s
tate_process
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
{
/* sending event to state machine */
int
rc
=
llc_conn_service
(
sk
,
skb
);
struct
llc_opt
*
llc
=
llc_sk
(
sk
);
struct
llc_conn_state_ev
*
ev
=
llc_conn_ev
(
skb
);
u8
flag
=
ev
->
flag
;
u8
status
=
ev
->
status
;
struct
llc_prim_if_block
*
ind_prim
=
ev
->
ind_prim
;
struct
llc_prim_if_block
*
cfm_prim
=
ev
->
cfm_prim
;
/*
* FIXME: this will vanish as soon I get rid of the last prim crap
*/
if
(
flag
!=
LLC_DATA_PRIM
+
1
&&
flag
!=
LLC_CONN_PRIM
+
1
&&
flag
!=
LLC_DISC_PRIM
+
1
)
llc_conn_free_ev
(
skb
);
#ifdef THIS_BREAKS_DISCONNECT_NOTIFICATION_BADLY
/* check if the connection was freed by the state machine by
* means of llc_conn_disc */
if
(
rc
==
2
)
{
printk
(
KERN_INFO
"%s: rc == 2
\n
"
,
__FUNCTION__
);
rc
=
-
ECONNABORTED
;
goto
out
;
}
#endif
/* THIS_BREAKS_DISCONNECT_NOTIFICATION_BADLY */
else
if
(
ind_prim
&&
cfm_prim
)
skb_get
(
skb
);
if
(
!
flag
)
/* indicate or confirm not required */
goto
out
;
rc
=
0
;
if
(
ind_prim
)
/* indication required */
if
(
ind_prim
)
{
/* indication required */
/*
* FIXME: this will be saner as soon I get rid of the double
* sock crap
*/
switch
(
flag
)
{
case
LLC_DATA_PRIM
+
1
:
llc_save_primitive
(
sk
,
skb
,
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 */
goto
out
;
/* data confirm has preconditions */
if
(
cfm_prim
->
prim
!=
LLC_DATA_PRIM
)
{
/* FIXME: see FIXMEs above */
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
);
goto
out
;
}
if
(
!
llc_data_accept_state
(
llc
->
state
))
{
/* In this state, we can send I pdu */
/* 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_kfree_skb:
kfree_skb
(
skb
);
out:
return
rc
;
}
void
llc_conn_send_pdu
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
{
llc_sock_assert
(
sk
);
/* queue PDU to send to MAC layer */
skb_queue_tail
(
&
sk
->
write_queue
,
skb
);
llc_conn_send_pdus
(
sk
);
...
...
@@ -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).
* Prepares service parameters (prim and prim_data). calling indication
* function will be done in llc_conn_s
end_ev
.
* function will be done in llc_conn_s
tate_process
.
*/
void
llc_conn_rtn_pdu
(
struct
sock
*
sk
,
struct
sk_buff
*
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_ind_prim
;
union
llc_u_prim_data
*
prim_data
=
prim
->
data
;
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
;
/* FIXME: indicate that we should send this to the upper layer */
ev
->
flag
=
LLC_DATA_PRIM
+
1
;
ev
->
ind_prim
=
(
void
*
)
1
;
}
/**
...
...
@@ -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
* @sk: connection
* @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
* success, 1 to indicate failure of at least one action or 2 if the
* connection was freed (llc_conn_disc was called)
* success, 1 to indicate failure of at least one action.
*/
static
int
llc_exec_conn_trans_actions
(
struct
sock
*
sk
,
struct
llc_conn_state_trans
*
trans
,
...
...
@@ -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
* @daddr: address of remote LLC (MAC + SAP)
* @laddr: address of local LLC (MAC + SAP)
...
...
@@ -405,7 +478,7 @@ static int llc_exec_conn_trans_actions(struct sock *sk,
* mac, remote sap, local mac, and local sap. Returns pointer for
* 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
sock
*
rc
=
NULL
;
...
...
@@ -419,8 +492,8 @@ struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr,
if
(
llc
->
laddr
.
lsap
==
laddr
->
lsap
&&
llc
->
daddr
.
lsap
==
daddr
->
lsap
&&
!
memcmp
(
llc
->
laddr
.
mac
,
laddr
->
mac
,
ETH_ALEN
)
&&
!
memcmp
(
llc
->
daddr
.
mac
,
daddr
->
mac
,
ETH_ALEN
))
{
llc_mac_match
(
llc
->
laddr
.
mac
,
laddr
->
mac
)
&&
llc_mac_match
(
llc
->
daddr
.
mac
,
daddr
->
mac
))
{
rc
=
llc
->
sk
;
break
;
}
...
...
@@ -432,6 +505,39 @@ struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr,
return
rc
;
}
/**
* llc_lookup_listener - Finds listener for local MAC + SAP
* @sap: SAP
* @laddr: address of local LLC (MAC + SAP)
*
* Search connection list of the SAP and finds connection listening on
* local mac, and local sap. Returns pointer for parent socket found,
* %NULL otherwise.
*/
struct
sock
*
llc_lookup_listener
(
struct
llc_sap
*
sap
,
struct
llc_addr
*
laddr
)
{
struct
sock
*
rc
=
NULL
;
struct
list_head
*
entry
;
spin_lock_bh
(
&
sap
->
sk_list
.
lock
);
if
(
list_empty
(
&
sap
->
sk_list
.
list
))
goto
out
;
list_for_each
(
entry
,
&
sap
->
sk_list
.
list
)
{
struct
llc_opt
*
llc
=
list_entry
(
entry
,
struct
llc_opt
,
node
);
if
(
llc
->
sk
->
type
!=
SOCK_STREAM
||
llc
->
sk
->
state
!=
TCP_LISTEN
||
llc
->
laddr
.
lsap
!=
laddr
->
lsap
||
!
llc_mac_match
(
llc
->
laddr
.
mac
,
laddr
->
mac
))
continue
;
rc
=
llc
->
sk
;
}
if
(
rc
)
sock_hold
(
rc
);
out:
spin_unlock_bh
(
&
sap
->
sk_list
.
lock
);
return
rc
;
}
/**
* llc_data_accept_state - designates if in this state data can be sent.
* @state: state of connection.
...
...
@@ -440,10 +546,8 @@ struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr,
*/
u8
llc_data_accept_state
(
u8
state
)
{
if
(
state
!=
LLC_CONN_STATE_NORMAL
&&
state
!=
LLC_CONN_STATE_BUSY
&&
state
!=
LLC_CONN_STATE_REJ
)
return
1
;
/* data_conn_refuse */
return
0
;
return
state
!=
LLC_CONN_STATE_NORMAL
&&
state
!=
LLC_CONN_STATE_BUSY
&&
state
!=
LLC_CONN_STATE_REJ
;
}
/**
...
...
net/llc/llc_if.c
View file @
ed54ae2e
...
...
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netdevice.h>
#include <linux/tcp.h>
#include <asm/errno.h>
#include <net/llc_if.h>
#include <net/llc_sap.h>
...
...
@@ -27,42 +28,6 @@
#include <net/llc_main.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.
* @nw_indicate: pointer to indicate function of upper layer.
...
...
@@ -70,7 +35,7 @@ static llc_prim_call_t llc_resp_prim[LLC_NBR_PRIMITIVES] = {
* @lsap: SAP number.
* @sap: pointer to allocated SAP (output argument).
*
* Interface function to upper layer.
e
ach one who wants to get a SAP
* Interface function to upper layer.
E
ach one who wants to get a SAP
* (for example NetBEUI) should call this function. Returns the opened
* SAP for success, NULL for failure.
*/
...
...
@@ -92,8 +57,6 @@ struct llc_sap *llc_sap_open(llc_prim_call_t nw_indicate,
goto
err
;
/* allocated a SAP; initialize it and clear out its memory pool */
sap
->
laddr
.
lsap
=
lsap
;
sap
->
req
=
llc_sap_req
;
sap
->
resp
=
llc_sap_resp
;
sap
->
ind
=
nw_indicate
;
sap
->
conf
=
nw_confirm
;
sap
->
parent_station
=
llc_station_get
();
...
...
@@ -110,7 +73,7 @@ struct llc_sap *llc_sap_open(llc_prim_call_t nw_indicate,
* llc_sap_close - close interface for upper layers.
* @sap: SAP to be closed.
*
* Close interface function to upper layer.
e
ach one who wants to
* Close interface function to upper layer.
E
ach one who wants to
* close an open SAP (for example NetBEUI) should call this function.
*/
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
* @prim: pointer to structure that contains service parameters.
*
* Request interface function to upper layer. each one who wants to
* request a service from LLC, must call this function. details of
* requested service is defined in input argument(prim). Returns 0 for
* success, 1 otherwise.
*/
static
int
llc_sap_req
(
struct
llc_prim_if_block
*
prim
)
{
int
rc
=
1
;
if
(
prim
->
prim
>
8
||
prim
->
prim
==
6
)
{
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
;
}
/**
* llc_unitdata_req_handler - unitdata request interface for upper layers
* @prim: pointer to structure that contains service parameters
* llc_build_and_send_ui_pkt - unitdata request interface for upper layers
* @sap: sap to use
* @skb: packet to send
* @addr: destination address
*
* Upper layers calls this function when upper layer wants to send data
* using connection-less mode communication (UI pdu). Returns 0 for
* success, 1 otherwise.
*/
static
int
llc_unitdata_req_handler
(
struct
llc_prim_if_block
*
prim
)
{
int
rc
=
1
;
struct
llc_sap_state_ev
*
ev
;
/* accept data frame from network layer to be sent using connection-
* using connection-less mode communication (UI pdu).
*
* Accept data frame from network layer to be sent using connection-
* less mode communication; timeout/retries handled by network layer;
* package primitive as an event and send to SAP event handler
*/
struct
llc_sap
*
sap
=
llc_sap_find
(
prim
->
data
->
udata
.
saddr
.
lsap
);
void
llc_build_and_send_ui_pkt
(
struct
llc_sap
*
sap
,
struct
sk_buff
*
skb
,
struct
sockaddr_llc
*
addr
)
{
union
llc_u_prim_data
prim_data
;
struct
llc_prim_if_block
prim
;
struct
llc_sap_state_ev
*
ev
=
llc_sap_ev
(
skb
);
skb
->
protocol
=
llc_proto_type
(
addr
->
sllc_arphrd
);
prim
.
data
=
&
prim_data
;
prim
.
sap
=
sap
;
prim
.
prim
=
LLC_DATAUNIT_PRIM
;
prim_data
.
udata
.
skb
=
skb
;
prim_data
.
udata
.
saddr
.
lsap
=
sap
->
laddr
.
lsap
;
prim_data
.
udata
.
daddr
.
lsap
=
addr
->
sllc_dsap
;
memcpy
(
prim_data
.
udata
.
saddr
.
mac
,
skb
->
dev
->
dev_addr
,
IFHWADDRLEN
);
memcpy
(
prim_data
.
udata
.
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
->
data
.
prim
.
prim
=
LLC_DATAUNIT_PRIM
;
ev
->
data
.
prim
.
type
=
LLC_PRIM_TYPE_REQ
;
ev
->
data
.
prim
.
data
=
prim
;
rc
=
0
;
llc_sap_send_ev
(
sap
,
prim
->
data
->
udata
.
skb
);
out:
return
rc
;
ev
->
data
.
prim
.
data
=
&
prim
;
llc_sap_state_process
(
sap
,
skb
);
}
/**
* llc_test_req_handler - TEST interface for upper layers.
* @prim: pointer to structure that contains service parameters.
* llc_build_and_send_test_pkt - TEST interface for upper layers.
* @sap: sap to use
* @skb: packet to send
* @addr: destination address
*
* This function is called when upper layer wants to send a TEST pdu.
* 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
;
struct
llc_sap_state_ev
*
ev
;
/* 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
);
union
llc_u_prim_data
prim_data
;
struct
llc_prim_if_block
prim
;
struct
llc_sap_state_ev
*
ev
=
llc_sap_ev
(
skb
);
skb
->
protocol
=
llc_proto_type
(
addr
->
sllc_arphrd
);
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
->
data
.
prim
.
prim
=
LLC_TEST_PRIM
;
ev
->
data
.
prim
.
type
=
LLC_PRIM_TYPE_REQ
;
ev
->
data
.
prim
.
data
=
prim
;
rc
=
0
;
llc_sap_send_ev
(
sap
,
prim
->
data
->
udata
.
skb
);
out:
return
rc
;
ev
->
data
.
prim
.
data
=
&
prim
;
llc_sap_state_process
(
sap
,
skb
);
}
/**
* llc_xid_req_handler - XID interface for upper layers
* @prim: pointer to structure that contains service parameters.
* llc_build_and_send_xid_pkt - XID interface for upper layers
* @sap: sap to use
* @skb: packet to send
* @addr: destination address
*
* This function is called when upper layer wants to send a XID pdu.
* 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
;
struct
llc_sap_state_ev
*
ev
;
/* package primitive as an event and send to SAP event handler */
struct
llc_sap
*
sap
=
llc_sap_find
(
prim
->
data
->
udata
.
saddr
.
lsap
);
union
llc_u_prim_data
prim_data
;
struct
llc_prim_if_block
prim
;
struct
llc_sap_state_ev
*
ev
=
llc_sap_ev
(
skb
);
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
->
data
.
prim
.
prim
=
LLC_XID_PRIM
;
ev
->
data
.
prim
.
type
=
LLC_PRIM_TYPE_REQ
;
ev
->
data
.
prim
.
data
=
prim
;
rc
=
0
;
llc_sap_send_ev
(
sap
,
prim
->
data
->
udata
.
skb
);
out:
return
rc
;
ev
->
data
.
prim
.
data
=
&
prim
;
llc_sap_state_process
(
sap
,
skb
);
}
/**
* 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
*
* This function is called when upper layer wants to send data using
* connection oriented communication mode.
d
uring sending data, connection
* connection oriented communication mode.
D
uring sending data, connection
* will be locked and received frames and expired timers will be queued.
* 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
* 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
;
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
);
lock_sock
(
sk
);
if
(
llc
->
state
==
LLC_CONN_STATE_ADM
)
goto
out
;
rc
=
-
EBUSY
;
...
...
@@ -267,169 +223,121 @@ static int llc_data_req_handler(struct llc_prim_if_block *prim)
llc
->
failed_data_req
=
1
;
goto
out
;
}
ev
=
llc_conn_ev
(
prim
->
data
->
data
.
skb
);
ev
=
llc_conn_ev
(
skb
);
ev
->
type
=
LLC_CONN_EV_TYPE_PRIM
;
ev
->
data
.
prim
.
prim
=
LLC_DATA_PRIM
;
ev
->
data
.
prim
.
type
=
LLC_PRIM_TYPE_REQ
;
ev
->
data
.
prim
.
data
=
prim
;
prim
->
data
->
data
.
skb
->
dev
=
llc
->
dev
;
rc
=
llc_conn_s
end_ev
(
sk
,
prim
->
data
->
data
.
skb
);
ev
->
data
.
prim
.
data
=
NULL
;
skb
->
dev
=
llc
->
dev
;
rc
=
llc_conn_s
tate_process
(
sk
,
skb
);
out:
release_sock
(
sk
);
return
rc
;
}
/**
* llc_confirm_impossible - Informs upper layer about failed connection
* @prim: pointer to structure that contains confirmation data.
*
* Informs upper layer about failing in connection establishment. This
* function is called by llc_conn_req_handler.
*/
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.
* llc_establish_connection - Called by upper layer to establish a conn
* @sk: connection
* @lmac: local mac address
* @dmac: destination mac address
* @dsap: destination sap
*
* Upper layer calls this to establish an LLC connection with a remote
* machine.
t
his function packages a proper event and sends it connection
* machine.
T
his function packages a proper event and sends it connection
* component state machine. Success or failure of connection
* establishment will inform to upper layer via calling it's confirm
* 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
;
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
;
int
rc
=
-
EISCONN
;
struct
llc_addr
laddr
,
daddr
;
/* network layer supplies addressing required to establish connection
;
* package as an event and send it to the connection event handler
*/
struct
sock
*
sk
;
memcpy
(
laddr
.
mac
,
sdev
->
dev_addr
,
sizeof
(
laddr
.
mac
))
;
laddr
.
lsap
=
prim
->
data
->
conn
.
saddr
.
lsap
;
memcpy
(
daddr
.
mac
,
prim
->
data
->
conn
.
daddr
.
mac
,
sizeof
(
d
addr
.
mac
));
daddr
.
lsap
=
prim
->
data
->
conn
.
daddr
.
lsap
;
sk
=
llc_find_sock
(
sap
,
&
daddr
,
&
laddr
);
if
(
sk
)
{
llc_confirm_impossible
(
prim
)
;
struct
sk_buff
*
skb
;
struct
llc_opt
*
llc
=
llc_sk
(
sk
);
struct
sock
*
existing
;
laddr
.
lsap
=
llc
->
sap
->
laddr
.
lsap
;
daddr
.
lsap
=
dsap
;
memcpy
(
daddr
.
mac
,
dmac
,
sizeof
(
daddr
.
mac
))
;
memcpy
(
laddr
.
mac
,
lmac
,
sizeof
(
l
addr
.
mac
));
existing
=
llc_lookup_established
(
llc
->
sap
,
&
daddr
,
&
laddr
)
;
if
(
existing
)
{
if
(
existing
->
state
==
TCP_ESTABLISHED
)
{
sk
=
existing
;
goto
out_put
;
}
rc
=
-
ENOMEM
;
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
;
}
else
sock_put
(
existing
);
}
sock_hold
(
sk
);
lock_sock
(
sk
);
/* assign new connection to it's SAP */
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
);
rc
=
-
ENOMEM
;
skb
=
alloc_skb
(
0
,
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_CONN_PRIM
;
ev
->
data
.
prim
.
type
=
LLC_PRIM_TYPE_REQ
;
ev
->
data
.
prim
.
data
=
prim
;
rc
=
llc_conn_s
end_ev
(
sk
,
skb
);
ev
->
data
.
prim
.
data
=
NULL
;
rc
=
llc_conn_s
tate_process
(
sk
,
skb
);
}
if
(
rc
)
{
llc_sap_unassign_sock
(
sap
,
sk
);
llc_sock_free
(
sk
);
llc_confirm_impossible
(
prim
);
}
release_sock
(
sk
);
out_put:
sock_put
(
sk
);
out:
return
rc
;
}
/**
* llc_
disc_req_handler
- Called by upper layer to close a connection
* @
prim: pointer to structure that contains service parameters.
* llc_
send_disc
- Called by upper layer to close a connection
* @
sk: connection to be closed
*
* Upper layer calls this when it wants to close an established LLC
* connection with a remote machine.
t
his function packages a proper event
* connection with a remote machine.
T
his function packages a proper event
* and sends it to connection component state machine. Returns 0 for
* 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
;
struct
llc_conn_state_ev
*
ev
;
struct
sk_buff
*
skb
;
struct
sock
*
sk
=
prim
->
data
->
disc
.
sk
;
sock_hold
(
sk
);
lock_sock
(
sk
);
if
(
llc_sk
(
sk
)
->
state
==
LLC_CONN_STATE_ADM
||
if
(
sk
->
type
!=
SOCK_STREAM
||
sk
->
state
!=
TCP_ESTABLISHED
||
llc_sk
(
sk
)
->
state
==
LLC_CONN_STATE_ADM
||
llc_sk
(
sk
)
->
state
==
LLC_CONN_OUT_OF_SVC
)
goto
out
;
/*
* Postpone unassigning the connection from its SAP and returning the
* connection until all ACTIONs have been completely executed
*/
skb
=
alloc_skb
(
1
,
GFP_ATOMIC
);
skb
=
alloc_skb
(
0
,
GFP_ATOMIC
);
if
(
!
skb
)
goto
out
;
sk
->
state
=
TCP_CLOSING
;
ev
=
llc_conn_ev
(
skb
);
ev
->
type
=
LLC_CONN_EV_TYPE_PRIM
;
ev
->
data
.
prim
.
prim
=
LLC_DISC_PRIM
;
ev
->
data
.
prim
.
type
=
LLC_PRIM_TYPE_REQ
;
ev
->
data
.
prim
.
data
=
prim
;
rc
=
llc_conn_s
end_ev
(
sk
,
skb
);
ev
->
data
.
prim
.
data
=
NULL
;
rc
=
llc_conn_s
tate_process
(
sk
,
skb
);
out:
release_sock
(
sk
);
sock_put
(
sk
);
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.
*
* Called when upper layer wants to reset an established LLC connection
* with a remote machine.
t
his function packages a proper event and sends
* with a remote machine.
T
his function packages a proper event and sends
* it to connection component state machine. Returns 0 for success, 1
* 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
;
struct
s
ock
*
sk
=
prim
->
data
->
res
.
sk
;
struct
s
k_buff
*
skb
=
alloc_skb
(
0
,
GFP_ATOMIC
)
;
lock_sock
(
sk
);
skb
=
alloc_skb
(
1
,
GFP_ATOMIC
);
if
(
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)
ev
->
data
.
prim
.
prim
=
LLC_RESET_PRIM
;
ev
->
data
.
prim
.
type
=
LLC_PRIM_TYPE_REQ
;
ev
->
data
.
prim
.
data
=
prim
;
rc
=
llc_conn_send_ev
(
sk
,
skb
);
}
release_sock
(
sk
);
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
);
rc
=
llc_conn_state_process
(
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_close
);
net/llc/llc_mac.c
View file @
ed54ae2e
...
...
@@ -27,14 +27,17 @@
#include <net/llc_s_ev.h>
#include <linux/trdevice.h>
#if
1
#if
0
#define dprintk(args...) printk(KERN_DEBUG args)
#else
#define dprintk(args...)
#endif
/* function prototypes */
u8
llc_mac_null_var
[
IFHWADDRLEN
];
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.
...
...
@@ -52,7 +55,7 @@ int mac_send_pdu(struct sk_buff *skb)
int
pri
=
GFP_ATOMIC
,
rc
=
-
1
;
if
(
!
skb
->
dev
)
{
dprintk
(
KERN_ERR
"%s: skb->dev == NULL!"
,
__FUNCTION__
);
dprintk
(
"%s: skb->dev == NULL!"
,
__FUNCTION__
);
goto
out
;
}
if
(
skb
->
sk
)
...
...
@@ -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
* @dev: device that receive pdu
* @pt: packet type
*
* When the system receives a 802.2 frame this function is called. It
* checks SAP and connection of received pdu and passes frame to
* llc_
pdu_router for sending to proper state machine. If frame is
*
related to a busy connection (a connection is sending data now),
*
function queues this frame in
connection's backlog.
* llc_
{station,sap,conn}_rcv for sending to proper state machine. If
*
the frame is related to a busy connection (a connection is sending
*
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
llc_sap
*
sap
;
struct
llc_pdu_sn
*
pdu
;
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.
*/
if
(
skb
->
pkt_type
==
PACKET_OTHERHOST
)
{
dprintk
(
KERN_INFO
"%s: PACKET_OTHERHOST
\n
"
,
__FUNCTION__
);
dprintk
(
"%s: PACKET_OTHERHOST
\n
"
,
__FUNCTION__
);
goto
drop
;
}
skb
=
skb_share_check
(
skb
,
GFP_ATOMIC
);
...
...
@@ -98,17 +102,19 @@ int mac_indicate(struct sk_buff *skb, struct net_device *dev,
fix_up_incoming_skb
(
skb
);
pdu
=
llc_pdu_sn_hdr
(
skb
);
if
(
!
pdu
->
dsap
)
{
/* NULL DSAP, refer to station */
if
(
llc_pdu_router
(
NULL
,
NULL
,
skb
,
0
))
goto
drop
;
dprintk
(
"%s: calling llc_station_rcv!
\n
"
,
__FUNCTION__
);
llc_station_rcv
(
skb
)
;
goto
out
;
}
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
;
}
llc_decode_pdu_type
(
skb
,
&
dest
);
if
(
dest
==
LLC_DEST_SAP
)
{
/* type 1 services */
if
(
llc_pdu_router
(
sap
,
NULL
,
skb
,
LLC_TYPE_1
))
goto
drop
;
dprintk
(
"%s: calling llc_sap_rcv!
\n
"
,
__FUNCTION__
);
llc_sap_rcv
(
sap
,
skb
)
;
}
else
if
(
dest
==
LLC_DEST_CONN
)
{
struct
llc_addr
saddr
,
daddr
;
struct
sock
*
sk
;
...
...
@@ -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_dsap
(
skb
,
&
daddr
.
lsap
);
sk
=
llc_find_sock
(
sap
,
&
saddr
,
&
daddr
);
if
(
!
sk
)
{
/* didn't find an active connection; allocate a
* connection to use; associate it with this SAP
sk
=
llc_lookup_established
(
sap
,
&
saddr
,
&
daddr
);
if
(
!
sk
)
{
/*
* Didn't find an active connection; verify if there
* is a listening socket for this llc addr
*/
sk
=
llc_sock_alloc
();
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
;
memcpy
(
&
llc_sk
(
sk
)
->
daddr
,
&
saddr
,
sizeof
(
saddr
));
}
sk
=
llc_sk_alloc
(
parent
->
family
,
GFP_ATOMIC
);
if
(
!
sk
)
{
sock_put
(
parent
);
goto
drop
;
}
llc
=
llc_sk
(
sk
);
memcpy
(
&
llc
->
laddr
,
&
daddr
,
sizeof
(
llc
->
laddr
));
memcpy
(
&
llc
->
daddr
,
&
saddr
,
sizeof
(
llc
->
daddr
));
llc_sap_assign_sock
(
sap
,
sk
);
sock_hold
(
sk
);
}
sock_put
(
parent
);
skb
->
sk
=
parent
;
}
else
skb
->
sk
=
sk
;
bh_lock_sock
(
sk
);
if
(
!
sk
->
lock
.
users
)
{
/* FIXME: Check this on SMP as it is now calling
* llc_pdu_router _with_ the lock held.
* 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
);
/* rc = */
llc_conn_rcv
(
sk
,
skb
);
rc
=
0
;
}
else
{
dprintk
(
KERN_INFO
"%s: add to backlog
\n
"
,
__FUNCTION__
);
dprintk
(
"%s: adding to backlog...
\n
"
,
__FUNCTION__
);
llc_set_backlog_type
(
skb
,
LLC_PACKET
);
sk_add_backlog
(
sk
,
skb
);
rc
=
0
;
...
...
@@ -191,53 +205,56 @@ static void fix_up_incoming_skb(struct sk_buff *skb)
}
}
/**
* llc_pdu_router - routes received pdus to the upper layers
* @sap: current sap component structure.
* @sk: current connection structure.
* @frame: received frame.
* @type: type of received frame, that is LLC_TYPE_1 or LLC_TYPE_2
/*
* llc_station_rcv - send received pdu to the station state machine
* @skb: received frame.
*
* Queues received PDUs from LLC_MAC PDU receive queue until queue is
* 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)
* Sends data unit to station state machine.
*/
int
llc_pdu_router
(
struct
llc_sap
*
sap
,
struct
sock
*
sk
,
struct
sk_buff
*
skb
,
u8
type
)
static
void
llc_station_rcv
(
struct
sk_buff
*
skb
)
{
struct
llc_pdu_sn
*
pdu
=
llc_pdu_sn_hdr
(
skb
);
int
rc
=
0
;
if
(
!
pdu
->
dsap
)
{
struct
llc_station
*
station
=
llc_station_get
();
struct
llc_station_state_ev
*
ev
=
llc_station_ev
(
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
);
llc_station_state_process
(
station
,
skb
);
}
ev
->
type
=
LLC_SAP_EV_TYPE_PDU
;
ev
->
data
.
pdu
.
reason
=
0
;
llc_sap_send_ev
(
sap
,
skb
);
}
else
if
(
type
==
LLC_TYPE_2
)
{
/**
* llc_conn_rcv - sends received pdus to the connection state machine
* @sk: current connection structure.
* @skb: received frame.
*
* 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
)
llc
->
dev
=
skb
->
dev
;
ev
->
type
=
LLC_CONN_EV_TYPE_PDU
;
ev
->
data
.
pdu
.
reason
=
0
;
rc
=
llc_conn_send_ev
(
sk
,
skb
);
}
else
rc
=
-
EINVAL
;
return
rc
;
return
llc_conn_state_process
(
sk
,
skb
);
}
/**
* llc_sap_rcv - sends received pdus to the sap state machine
* @sap: current sap component structure.
* @skb: received frame.
*
* 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
);
}
/**
...
...
net/llc/llc_main.c
View file @
ed54ae2e
...
...
@@ -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 */
#undef LLC_REFCNT_DEBUG
#ifdef LLC_REFCNT_DEBUG
static
atomic_t
llc_sock_nr
;
#endif
/**
* llc_sap_alloc - allocates and initializes sap.
*
...
...
@@ -136,7 +141,7 @@ struct llc_sap *llc_sap_find(u8 sap_value)
*
* This function processes frames that has received and timers that has
* 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).
*/
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
->
state
>
1
)
/* not closed */
rc
=
llc_
pdu_router
(
llc
->
sap
,
sk
,
skb
,
LLC_TYPE_2
);
rc
=
llc_
conn_rcv
(
sk
,
skb
);
else
kfree_skb
(
skb
);
}
else
if
(
llc_backlog_type
(
skb
)
==
LLC_EVENT
)
{
/* timer expiration event */
if
(
llc
->
state
>
1
)
/* not closed */
rc
=
llc_conn_s
end_ev
(
sk
,
skb
);
rc
=
llc_conn_s
tate_process
(
sk
,
skb
);
else
llc_conn_free_ev
(
skb
);
kfree_skb
(
skb
);
...
...
@@ -165,10 +170,12 @@ static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb)
}
/**
* llc_s
ock_init - Initialize
a socket with default llc values.
* llc_s
k_init - Initializes
a socket with default llc values.
* @sk: socket to intiailize.
*
* Initializes a socket with default llc values.
*/
int
llc_s
oc
k_init
(
struct
sock
*
sk
)
int
llc_sk_init
(
struct
sock
*
sk
)
{
struct
llc_opt
*
llc
=
kmalloc
(
sizeof
(
*
llc
),
GFP_ATOMIC
);
int
rc
=
-
ENOMEM
;
...
...
@@ -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
* 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
)
goto
out
;
if
(
llc_s
oc
k_init
(
sk
))
goto
decmod
;
if
(
llc_sk_init
(
sk
))
goto
outsk
;
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:
return
sk
;
outsk:
sk_free
(
sk
);
sk
=
NULL
;
decmod:
MOD_DEC_USE_COUNT
;
goto
out
;
}
/**
*
__llc_soc
k_free - Frees a LLC socket
*
llc_s
k_free - Frees a LLC socket
* @sk - socket to free
*
* 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
);
llc
->
state
=
LLC_CONN_OUT_OF_SVC
;
/*
s
top all (possibly) running timers */
/*
S
top all (possibly) running timers */
llc_conn_ac_stop_all_timers
(
sk
,
NULL
);
/* handle return of frames on lists */
#if 0
#ifdef DEBUG_LLC_CONN_ALLOC
printk
(
KERN_INFO
"%s: unackq=%d, txq=%d
\n
"
,
__FUNCTION__
,
skb_queue_len
(
&
llc
->
pdu_unack_q
),
skb_queue_len
(
&
sk
->
write_queue
));
#endif
skb_queue_purge
(
&
sk
->
receive_queue
);
skb_queue_purge
(
&
sk
->
write_queue
);
skb_queue_purge
(
&
llc
->
pdu_unack_q
);
if
(
free
)
#ifdef LLC_REFCNT_DEBUG
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_s
oc
k_reset - resets a connection
* llc_sk_reset - resets a connection
* @sk: LLC socket to reset
*
* Resets a connection to the out of service state. Stops its timers
* and frees any frames in the queues of the connection.
*/
void
llc_s
oc
k_reset
(
struct
sock
*
sk
)
void
llc_sk_reset
(
struct
sock
*
sk
)
{
struct
llc_opt
*
llc
=
llc_sk
(
sk
);
...
...
@@ -286,8 +315,6 @@ void llc_sock_reset(struct sock *sk)
static
int
llc_rtn_all_conns
(
struct
llc_sap
*
sap
)
{
int
rc
=
0
;
union
llc_u_prim_data
prim_data
;
struct
llc_prim_if_block
prim
;
struct
list_head
*
entry
,
*
tmp
;
spin_lock_bh
(
&
sap
->
sk_list
.
lock
);
...
...
@@ -296,12 +323,8 @@ static int llc_rtn_all_conns(struct llc_sap *sap)
list_for_each_safe
(
entry
,
tmp
,
&
sap
->
sk_list
.
list
)
{
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
;
if
(
sap
->
req
(
&
prim
))
if
(
llc_send_disc
(
llc
->
sk
))
rc
=
1
;
}
out:
...
...
@@ -320,14 +343,14 @@ struct llc_station *llc_station_get(void)
}
/**
* llc_station_s
end_ev
: queue event and try to process queue.
* llc_station_s
tate_process
: queue event and try to process queue.
* @station: Address of the station
* @skb: Address of the event
*
* Queues an event (on the station event queue) for handling by the
* station state machine and attempts to process any queued-up events.
*/
void
llc_station_s
end_ev
(
struct
llc_station
*
station
,
struct
sk_buff
*
skb
)
void
llc_station_s
tate_process
(
struct
llc_station
*
station
,
struct
sk_buff
*
skb
)
{
spin_lock_bh
(
&
station
->
ev_q
.
lock
);
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)
static
struct
packet_type
llc_packet_type
=
{
.
type
=
__constant_htons
(
ETH_P_802_2
),
.
func
=
mac_indicate
,
.
func
=
llc_rcv
,
.
data
=
(
void
*
)
1
,
};
static
struct
packet_type
llc_tr_packet_type
=
{
.
type
=
__constant_htons
(
ETH_P_TR_802_2
),
.
func
=
mac_indicate
,
.
func
=
llc_rcv
,
.
data
=
(
void
*
)
1
,
};
...
...
@@ -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
.
ev_q
.
list
);
spin_lock_init
(
&
llc_main_station
.
ev_q
.
lock
);
skb
=
alloc_skb
(
1
,
GFP_ATOMIC
);
skb
=
alloc_skb
(
0
,
GFP_ATOMIC
);
if
(
!
skb
)
goto
err
;
llc_build_offset_table
();
...
...
net/llc/llc_pdu.c
View file @
ed54ae2e
...
...
@@ -18,7 +18,7 @@
#include <net/llc_mac.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
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)
u8
pdu_type
;
struct
llc_pdu_sn
*
pdu
;
if
(
llc_pdu_decode_pdu_type
(
skb
,
&
pdu_type
))
goto
out
;
llc_pdu_decode_pdu_type
(
skb
,
&
pdu_type
);
pdu
=
llc_pdu_sn_hdr
(
skb
);
switch
(
pdu_type
)
{
...
...
@@ -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
);
break
;
}
out:
;
}
/**
...
...
@@ -86,15 +83,12 @@ out:;
* 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.
*/
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
;
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
);
switch
(
pdu_type
)
{
...
...
@@ -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
;
break
;
}
out:
return
0
;
}
/**
* llc_pdu_decode_cr_bit - extracs command response bit from LLC header
* llc_pdu_decode_cr_bit - extrac
t
s command response bit from LLC header
* @skb: input skb that c/r bit must be extracted from it.
* @cr_bit: command/response bit (0 or 1).
*
* This function extracts command/response bit from LLC header. this bit
* 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
;
return
0
;
}
/**
...
...
@@ -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.
*/
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
))
memcpy
(
sa
,
((
struct
ethhdr
*
)
skb
->
mac
.
raw
)
->
h_source
,
ETH_ALEN
);
else
if
(
skb
->
protocol
==
ntohs
(
ETH_P_TR_802_2
))
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)
*
* 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
))
memcpy
(
da
,
((
struct
ethhdr
*
)
skb
->
mac
.
raw
)
->
h_dest
,
ETH_ALEN
);
else
if
(
skb
->
protocol
==
ntohs
(
ETH_P_TR_802_2
))
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)
* This function extracts destination SAP of input frame. right bit of
* 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
;
return
0
;
}
/**
...
...
@@ -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.
* @ssap: source SAP (output argument).
*
* This function extracts source SAP of input frame.
r
ight bit of SSAP is
* This function extracts source SAP of input frame.
R
ight bit of SSAP is
* 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
;
return
0
;
}
/**
...
...
@@ -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.
*/
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
);
pdu
->
ctrl_1
=
LLC_PDU_TYPE_U
;
pdu
->
ctrl_1
|=
LLC_1_PDU_CMD_UI
;
return
0
;
}
/**
...
...
@@ -206,7 +192,7 @@ int llc_pdu_init_as_ui_cmd(struct sk_buff *skb)
* This function sets third,fourth,fifth and sixth bytes of LLC header as
* 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
)
{
struct
llc_xid_info
*
xid_info
;
...
...
@@ -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
->
rw
=
rx_window
<<
1
;
/* size of recieve window */
skb_put
(
skb
,
3
);
return
0
;
}
/**
...
...
@@ -229,14 +214,13 @@ int llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported,
*
* 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
);
pdu
->
ctrl_1
=
LLC_PDU_TYPE_U
;
pdu
->
ctrl_1
|=
LLC_1_PDU_CMD_TEST
;
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)
*
* 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
);
pdu
->
ctrl_1
=
LLC_PDU_TYPE_U
;
pdu
->
ctrl_1
|=
LLC_2_PDU_CMD_DISC
;
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
* @p_bit: The P bit to set in the 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)
*
* 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
);
...
...
@@ -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_1
|=
(
ns
<<
1
)
&
0xFE
;
/* set N(S) in bits 2..8 */
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
* @p_bit: The P bit to set in the PDU
* @nr: The seq. number of the expected I PDU from the remote
*
* 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
);
...
...
@@ -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_1
&=
0x0F
;
/* setting bits 5..8 to zero(reserved) */
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
* @p_bit: The P bit to set in the PDU
* @nr: The seq. number of the expected I PDU from the remote
*
* 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
);
...
...
@@ -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_1
&=
0x0F
;
/* setting bits 5..8 to zero(reserved) */
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
* @p_bit: The P bit to set in the PDU
* @nr: The seq. number of the expected I PDU from the remote
*
* 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
);
...
...
@@ -336,52 +316,49 @@ 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_1
&=
0x0F
;
/* setting bits 5..8 to zero(reserved) */
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
* @p_bit: The P bit to set in the PDU
*
* 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
);
pdu
->
ctrl_1
=
LLC_PDU_TYPE_U
;
pdu
->
ctrl_1
|=
LLC_2_PDU_CMD_SABME
;
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
* @f_bit: The F bit to set in the PDU
*
* 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
);
pdu
->
ctrl_1
=
LLC_PDU_TYPE_U
;
pdu
->
ctrl_1
|=
LLC_2_PDU_RSP_DM
;
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
* @svcs_supported: The class of the LLC (I or II)
* @rx_window: The size of the receive window of the LLC
*
* 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
)
{
struct
llc_xid_info
*
xid_info
;
...
...
@@ -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
->
rw
=
rx_window
<<
1
;
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
* @ev_skb: The received TEST command PDU frame
*
* 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
;
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)
memcpy
(((
u8
*
)
pdu
)
+
3
,
((
u8
*
)
ev_pdu
)
+
3
,
dsize
);
skb_put
(
skb
,
dsize
);
}
return
0
;
}
/**
* pdu_init_as_frmr_rsp - builds FRMR response PDU
* @
pdu_frame
: Address of the frame to build
*
llc_
pdu_init_as_frmr_rsp - builds FRMR response PDU
* @
skb
: Address of the frame to build
* @prev_pdu: The rejected PDU frame
* @f_bit: The F bit to set in the PDU
* @vs: tx state vari value for the data link conn at the rejecting LLC
...
...
@@ -435,7 +410,7 @@ int llc_pdu_init_as_test_rsp(struct sk_buff *skb, struct sk_buff *ev_skb)
*
* 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
)
{
struct
llc_frmr_info
*
frmr_info
;
...
...
@@ -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_Ns_IND
(
frmr_info
,
vzyxw
);
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
* @f_bit: The F bit to set in the PDU
* @nr: The seq. number of the expected data PDU from the remote
*
* 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
);
...
...
@@ -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_1
&=
0x0F
;
/* setting bits 5..8 to zero(reserved) */
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
* @f_bit: The F bit to set in the PDU
* @nr: The seq. number of the expected data PDU from the remote
*
* 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
);
...
...
@@ -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_1
&=
0x0F
;
/* setting bits 5..8 to zero(reserved) */
pdu
->
ctrl_2
|=
(
nr
<<
1
)
&
0xFE
;
/* set N(R) in bits 10..16 */
return
0
;
}
/**
* pdu_init_as_rnr_rsp - builds RNR response pdu
* @
pdu_frame
: Address of the frame to build
*
llc_
pdu_init_as_rnr_rsp - builds RNR response pdu
* @
skb
: Address of the frame to build
* @f_bit: The F bit to set in the PDU
* @nr: The seq. number of the expected data PDU from the remote
*
* 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
);
...
...
@@ -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_1
&=
0x0F
;
/* setting bits 5..8 to zero(reserved) */
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
* @f_bit: The F bit to set in the PDU
*
* 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
);
pdu
->
ctrl_1
=
LLC_PDU_TYPE_U
;
pdu
->
ctrl_1
|=
LLC_2_PDU_RSP_UA
;
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)
* @skb: input skb that type of it must be designated.
* @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
);
...
...
@@ -561,7 +531,6 @@ static int llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type)
*
type
=
LLC_PDU_TYPE_S
;
}
else
*
type
=
LLC_PDU_TYPE_I
;
return
0
;
}
/**
...
...
@@ -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.
*/
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 */
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)
}
out:
*
dest
=
type
;
return
0
;
}
/**
...
...
net/llc/llc_s_ac.c
View file @
ed54ae2e
...
...
@@ -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
,
prim_data
->
daddr
.
lsap
,
LLC_PDU_CMD
);
rc
=
llc_pdu_init_as_ui_cmd
(
skb
);
if
(
rc
)
goto
out
;
llc_pdu_init_as_ui_cmd
(
skb
);
rc
=
lan_hdrs_init
(
skb
,
prim_data
->
saddr
.
mac
,
prim_data
->
daddr
.
mac
);
if
(
!
rc
)
llc_sap_send_pdu
(
sap
,
skb
);
out:
return
rc
;
}
...
...
@@ -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
,
prim_data
->
daddr
.
lsap
,
LLC_PDU_CMD
);
rc
=
llc_pdu_init_as_xid_cmd
(
skb
,
LLC_XID_NULL_CLASS_2
,
0
);
if
(
rc
)
goto
out
;
llc_pdu_init_as_xid_cmd
(
skb
,
LLC_XID_NULL_CLASS_2
,
0
);
rc
=
lan_hdrs_init
(
skb
,
prim_data
->
saddr
.
mac
,
prim_data
->
daddr
.
mac
);
if
(
!
rc
)
llc_sap_send_pdu
(
sap
,
skb
);
out:
return
rc
;
}
...
...
@@ -118,9 +112,7 @@ int llc_sap_action_send_xid_r(struct llc_sap *sap, struct sk_buff *skb)
nskb
->
dev
=
skb
->
dev
;
llc_pdu_header_init
(
nskb
,
LLC_PDU_TYPE_U
,
sap
->
laddr
.
lsap
,
dsap
,
LLC_PDU_RSP
);
rc
=
llc_pdu_init_as_xid_rsp
(
nskb
,
LLC_XID_NULL_CLASS_2
,
0
);
if
(
rc
)
goto
out
;
llc_pdu_init_as_xid_rsp
(
nskb
,
LLC_XID_NULL_CLASS_2
,
0
);
rc
=
lan_hdrs_init
(
nskb
,
mac_sa
,
mac_da
);
if
(
!
rc
)
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)
llc_pdu_header_init
(
skb
,
LLC_PDU_TYPE_U
,
prim_data
->
saddr
.
lsap
,
prim_data
->
daddr
.
lsap
,
LLC_PDU_CMD
);
rc
=
llc_pdu_init_as_test_cmd
(
skb
);
if
(
rc
)
goto
out
;
llc_pdu_init_as_test_cmd
(
skb
);
rc
=
lan_hdrs_init
(
skb
,
prim_data
->
saddr
.
mac
,
prim_data
->
daddr
.
mac
);
if
(
!
rc
)
llc_sap_send_pdu
(
sap
,
skb
);
out:
return
rc
;
}
...
...
@@ -171,9 +160,7 @@ int llc_sap_action_send_test_r(struct llc_sap *sap, struct sk_buff *skb)
nskb
->
dev
=
skb
->
dev
;
llc_pdu_header_init
(
nskb
,
LLC_PDU_TYPE_U
,
sap
->
laddr
.
lsap
,
dsap
,
LLC_PDU_RSP
);
rc
=
llc_pdu_init_as_test_rsp
(
nskb
,
skb
);
if
(
rc
)
goto
out
;
llc_pdu_init_as_test_rsp
(
nskb
,
skb
);
rc
=
lan_hdrs_init
(
nskb
,
mac_sa
,
mac_da
);
if
(
!
rc
)
llc_sap_send_pdu
(
sap
,
nskb
);
...
...
net/llc/llc_sap.c
View file @
ed54ae2e
...
...
@@ -23,7 +23,6 @@
#include <net/llc_pdu.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_exec_sap_trans_actions
(
struct
llc_sap
*
sap
,
struct
llc_sap_state_trans
*
trans
,
...
...
@@ -52,8 +51,7 @@ void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk)
* @sap: SAP
* @sk: pointer to connection
*
* This function removes a connection from connection_list of a SAP.
* List locking is performed by caller (rtn_all_conns).
* This function removes a connection from sk_list.list of a SAP.
*/
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_s
end_ev
- sends event to SAP state machine
* llc_sap_s
tate_process
- sends event to SAP state machine
* @sap: pointer to SAP
* @skb: pointer to occurred event
*
* After executing actions of the event, upper layer will be indicated
* if needed(on receiving an UI frame).
*/
void
llc_sap_s
end_ev
(
struct
llc_sap
*
sap
,
struct
sk_buff
*
skb
)
void
llc_sap_s
tate_process
(
struct
llc_sap
*
sap
,
struct
sk_buff
*
skb
)
{
struct
llc_sap_state_ev
*
ev
=
llc_sap_ev
(
skb
);
llc_sap_next_state
(
sap
,
skb
);
if
(
ev
->
ind_cfm_flag
==
LLC_IND
)
{
skb_get
(
skb
);
if
(
ev
->
ind_cfm_flag
==
LLC_IND
)
sap
->
ind
(
ev
->
prim
);
}
llc_sap_free_ev
(
sap
,
skb
);
else
if
(
ev
->
type
==
LLC_SAP_EV_TYPE_PDU
)
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)
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
* @sap: pointer to 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
* 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
))
{
/* got event match; return it */
rc
=
next_trans
[
i
];
...
...
net/llc/llc_sock.c
View file @
ed54ae2e
...
...
@@ -11,6 +11,7 @@
* connections.
*
* 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
* GNU General Public License as published by the Free Software Foundation.
...
...
@@ -38,6 +39,7 @@
#include <net/llc_sap.h>
#include <net/llc_pdu.h>
#include <net/llc_conn.h>
#include <net/llc_mac.h>
#include <linux/llc.h>
#include <linux/if_arp.h>
#include <linux/rtnetlink.h>
...
...
@@ -46,7 +48,6 @@
/* 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_link_no_max
[
256
];
static
u8
llc_ui_addrany
[
IFHWADDRLEN
];
static
struct
sockaddr_llc
llc_ui_addrnull
;
static
struct
proto_ops
llc_ui_ops
;
static
struct
sock
*
llc_ui_sockets
;
...
...
@@ -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_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_disc
(
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
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
...
...
@@ -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.
*/
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
]
++
;
}
/**
* 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
* @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
));
}
/**
* 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
* @sk: Socket which contains a valid llc socket type.
...
...
@@ -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.
* 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
;
...
...
@@ -140,138 +107,33 @@ static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr)
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
* @sap: Sap the socket is bound to.
* @sk: Connection the socket is using.
* @skb: Data the user wishes to send.
* @addr: Source and destination fields provided by the user.
* @noblock: can we block waiting for data?
*
* Send data via reliable llc2 connection.
* Returns 0 upon success, non-zero if action did not succeed.
*/
static
int
llc_ui_send_data
(
struct
llc_sap
*
sap
,
struct
sock
*
sk
,
struct
s
k_buff
*
skb
,
struct
sockaddr_llc
*
addr
)
static
int
llc_ui_send_data
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
,
struct
s
ockaddr_llc
*
addr
,
int
noblock
)
{
union
llc_u_prim_data
prim_data
;
struct
llc_prim_if_block
prim
;
struct
llc_ui_opt
*
llc_ui
=
llc_ui_sk
(
sk
);
struct
llc_opt
*
llc_core
=
llc_sk
(
llc_ui
->
core_sk
);
int
rc
;
struct
llc_opt
*
llc
=
llc_sk
(
sk
);
int
rc
=
0
;
prim
.
data
=
&
prim_data
;
prim
.
sap
=
sap
;
prim
.
prim
=
LLC_DATA_PRIM
;
prim_data
.
data
.
skb
=
skb
;
prim_data
.
data
.
pri
=
0
;
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
);
skb
->
protocol
=
llc_proto_type
(
addr
->
sllc_arphrd
);
if
(
llc_data_accept_state
(
llc
->
state
)
||
llc
->
p_flag
)
{
int
timeout
=
sock_sndtimeo
(
sk
,
noblock
);
rc
=
llc_ui_wait_for_busy_core
(
sk
,
timeout
);
}
if
(
!
rc
)
goto
try
;
if
(
!
llc_ui
->
core_sk
)
rc
=
-
ENOTCONN
;
out:
sock_put
(
sk
);
rc
=
llc_build_and_send_pkt
(
sk
,
skb
);
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
* @sap: Sap number to search for.
...
...
@@ -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.
* 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
llc_sap
*
s
=
NULL
;
read_lock_bh
(
&
llc_ui_sockets_lock
);
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
;
if
(
llc
_ui
->
sap
->
laddr
.
lsap
==
sap
)
{
s
=
llc
_ui
->
sap
;
if
(
llc
->
sap
->
laddr
.
lsap
==
sap
)
{
s
=
llc
->
sap
;
break
;
}
}
...
...
@@ -306,13 +168,13 @@ static struct sock *__llc_ui_find_sk_by_exact(struct llc_addr *laddr,
struct
sock
*
sk
;
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
&&
llc
_ui
->
addr
.
sllc_dsap
==
daddr
->
lsap
&&
llc_
ui_mac_null
(
llc_ui
->
addr
.
sllc_mmac
)
&&
llc_
ui_mac_match
(
llc_ui
->
addr
.
sllc_smac
,
laddr
->
mac
)
&&
llc_
ui_mac_match
(
llc_ui
->
addr
.
sllc_dmac
,
daddr
->
mac
))
if
(
llc
->
addr
.
sllc_ssap
==
laddr
->
lsap
&&
llc
->
addr
.
sllc_dsap
==
daddr
->
lsap
&&
llc_
mac_null
(
llc
->
addr
.
sllc_mmac
)
&&
llc_
mac_match
(
llc
->
addr
.
sllc_smac
,
laddr
->
mac
)
&&
llc_
mac_match
(
llc
->
addr
.
sllc_dmac
,
daddr
->
mac
))
break
;
}
return
sk
;
...
...
@@ -335,31 +197,31 @@ static struct sock *__llc_ui_find_sk_by_addr(struct llc_addr *laddr,
struct
sock
*
sk
,
*
tmp_sk
;
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
;
if
(
llc_
ui_mac_null
(
llc_ui
->
addr
.
sllc_smac
))
{
if
(
!
llc_
ui_mac_null
(
llc_ui
->
addr
.
sllc_mmac
)
&&
!
llc_
ui_mac_match
(
llc_ui
->
addr
.
sllc_mmac
,
if
(
llc_
mac_null
(
llc
->
addr
.
sllc_smac
))
{
if
(
!
llc_
mac_null
(
llc
->
addr
.
sllc_mmac
)
&&
!
llc_
mac_match
(
llc
->
addr
.
sllc_mmac
,
laddr
->
mac
))
continue
;
break
;
}
if
(
dev
&&
!
llc_
ui_mac_null
(
llc_ui
->
addr
.
sllc_mmac
)
&&
llc_
ui_mac_match
(
llc_ui
->
addr
.
sllc_mmac
,
laddr
->
mac
)
&&
llc_
ui_mac_match
(
llc_ui
->
addr
.
sllc_smac
,
dev
->
dev_addr
))
if
(
dev
&&
!
llc_
mac_null
(
llc
->
addr
.
sllc_mmac
)
&&
llc_
mac_match
(
llc
->
addr
.
sllc_mmac
,
laddr
->
mac
)
&&
llc_
mac_match
(
llc
->
addr
.
sllc_smac
,
dev
->
dev_addr
))
break
;
if
(
dev
->
flags
&
IFF_LOOPBACK
)
break
;
if
(
!
llc_
ui_mac_match
(
llc_ui
->
addr
.
sllc_smac
,
laddr
->
mac
))
if
(
!
llc_
mac_match
(
llc
->
addr
.
sllc_smac
,
laddr
->
mac
))
continue
;
tmp_sk
=
__llc_ui_find_sk_by_exact
(
laddr
,
daddr
);
if
(
tmp_sk
)
{
sk
=
tmp_sk
;
break
;
}
if
(
llc_
ui_mac_null
(
llc_ui
->
addr
.
sllc_dmac
))
if
(
llc_
mac_null
(
llc
->
addr
.
sllc_dmac
))
break
;
}
return
sk
;
...
...
@@ -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.
*/
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
);
sk
->
next
=
llc_ui_sockets
;
...
...
@@ -417,7 +279,7 @@ static inline void llc_ui_insert_socket(struct sock *sk)
*
* 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
);
if
(
sk
->
pprev
)
{
...
...
@@ -425,7 +287,8 @@ static inline void llc_ui_remove_socket(struct sock *sk)
sk
->
next
->
pprev
=
sk
->
pprev
;
*
sk
->
pprev
=
sk
->
next
;
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
*/
sock_put
(
sk
);
...
...
@@ -433,38 +296,13 @@ static inline void llc_ui_remove_socket(struct sock *sk)
write_unlock_bh
(
&
llc_ui_sockets_lock
);
}
/**
* 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
)
static
void
llc_ui_sk_init
(
struct
socket
*
sock
,
struct
sock
*
sk
)
{
struct
sock
*
sk
=
(
struct
sock
*
)
data
;
if
(
!
atomic_read
(
&
sk
->
wmem_alloc
)
&&
!
atomic_read
(
&
sk
->
rmem_alloc
)
&&
sk
->
dead
)
llc_ui_destroy_sk
(
sk
);
else
{
sk
->
timer
.
expires
=
jiffies
+
SOCK_DESTROY_TIME
;
add_timer
(
&
sk
->
timer
);
}
sk
->
type
=
sock
->
type
;
sk
->
sleep
=
&
sock
->
wait
;
sk
->
socket
=
sock
;
sock
->
sk
=
sk
;
sock
->
ops
=
&
llc_ui_ops
;
}
/**
...
...
@@ -479,31 +317,17 @@ static void llc_ui_destroy_timer(unsigned long data)
static
int
llc_ui_create
(
struct
socket
*
sock
,
int
protocol
)
{
struct
sock
*
sk
;
struct
llc_ui_opt
*
llc_ui
;
int
rc
=
-
ESOCKTNOSUPPORT
;
MOD_INC_USE_COUNT
;
if
(
sock
->
type
!=
SOCK_DGRAM
&&
sock
->
type
!=
SOCK_STREAM
)
goto
decmod
;
if
(
sock
->
type
==
SOCK_DGRAM
||
sock
->
type
==
SOCK_STREAM
)
{
rc
=
-
ENOMEM
;
sk
=
sk_alloc
(
PF_LLC
,
GFP_KERNEL
,
1
,
NULL
);
if
(
!
sk
)
goto
decmod
;
llc_ui
=
kmalloc
(
sizeof
(
*
llc_ui
),
GFP_KERNEL
);
if
(
!
llc_ui
)
goto
outsk
;
memset
(
llc_ui
,
0
,
sizeof
(
*
llc_ui
));
sk
=
llc_sk_alloc
(
PF_LLC
,
GFP_KERNEL
);
if
(
sk
)
{
rc
=
0
;
sock_init_data
(
sock
,
sk
);
llc_ui_sk
(
sk
)
=
llc_ui
;
sock
->
ops
=
&
llc_ui_ops
;
out:
llc_ui_sk_init
(
sock
,
sk
);
}
}
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)
static
int
llc_ui_release
(
struct
socket
*
sock
)
{
struct
sock
*
sk
=
sock
->
sk
;
struct
llc_
ui_opt
*
llc_ui
;
struct
llc_
opt
*
llc
;
if
(
!
sk
)
goto
out
;
llc_ui
=
llc_ui_sk
(
sk
);
if
(
llc_ui
->
core_sk
&&
!
llc_ui_send_disc
(
sk
))
llc_ui_wait_for_disc
(
sk
,
255
);
sock_hold
(
sk
);
lock_sock
(
sk
);
llc
=
llc_sk
(
sk
);
dprintk
(
"%s: closing local(%02X) remote(%02X)
\n
"
,
__FUNCTION__
,
llc
->
laddr
.
lsap
,
llc
->
daddr
.
lsap
);
if
(
!
llc_send_disc
(
sk
))
llc_ui_wait_for_disc
(
sk
,
sk
->
rcvtimeo
);
release_sock
(
sk
);
if
(
!
sk
->
zapped
)
{
llc_sap_unassign_sock
(
llc
->
sap
,
sk
);
llc_ui_remove_socket
(
sk
);
if
(
llc_ui
->
sap
&&
!
llc_ui_find_sap
(
llc_ui
->
sap
->
laddr
.
lsap
))
llc_sap_close
(
llc_ui
->
sap
);
sock_orphan
(
sk
);
sock
->
sk
=
NULL
;
if
(
!
atomic_read
(
&
sk
->
wmem_alloc
)
&&
!
atomic_read
(
&
sk
->
rmem_alloc
)
&&
sk
->
dead
)
llc_ui_destroy_sk
(
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:
return
0
;
}
...
...
@@ -590,7 +412,7 @@ static int llc_ui_autoport(void)
static
int
llc_ui_autobind
(
struct
socket
*
sock
,
struct
sockaddr_llc
*
addr
)
{
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
net_device
*
dev
=
NULL
;
int
rc
=
-
EINVAL
;
...
...
@@ -598,14 +420,14 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
if
(
!
sk
->
zapped
)
goto
out
;
/* bind to a specific mac, optional. */
if
(
!
llc_
ui_
mac_null
(
addr
->
sllc_smac
))
{
if
(
!
llc_mac_null
(
addr
->
sllc_smac
))
{
rtnl_lock
();
dev
=
dev_getbyhwaddr
(
addr
->
sllc_arphrd
,
addr
->
sllc_smac
);
rtnl_unlock
();
rc
=
-
ENETUNREACH
;
if
(
!
dev
)
goto
out
;
llc
_ui
->
dev
=
dev
;
llc
->
dev
=
dev
;
}
/* bind to a specific sap, optional. */
if
(
!
addr
->
sllc_ssap
)
{
...
...
@@ -626,11 +448,11 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
struct
sock
*
ask
;
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
;
memset
(
&
laddr
,
0
,
sizeof
(
laddr
));
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
)
{
rc
=
-
EOPNOTSUPP
;
goto
out
;
...
...
@@ -646,10 +468,16 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
goto
out
;
}
}
memcpy
(
&
llc_ui
->
addr
,
addr
,
sizeof
(
*
addr
));
llc_ui
->
sap
=
sap
;
llc
->
laddr
.
lsap
=
addr
->
sllc_ssap
;
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
;
llc_ui_insert_socket
(
sk
);
/* assign new connection to it's SAP */
llc_sap_assign_sock
(
sap
,
sk
);
out:
return
rc
;
}
...
...
@@ -678,6 +506,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
struct
sock
*
sk
=
sock
->
sk
;
int
rc
=
-
EINVAL
;
dprintk
(
"%s: binding %02X
\n
"
,
__FUNCTION__
,
addr
->
sllc_ssap
);
if
(
!
sk
->
zapped
||
addrlen
!=
sizeof
(
*
addr
))
goto
out
;
rc
=
-
EAFNOSUPPORT
;
...
...
@@ -711,9 +540,9 @@ static int llc_ui_shutdown(struct socket *sock, int how)
rc
=
-
EINVAL
;
if
(
how
!=
2
)
goto
out
;
rc
=
llc_
ui_
send_disc
(
sk
);
rc
=
llc_send_disc
(
sk
);
if
(
!
rc
)
llc_ui_wait_for_disc
(
sk
,
255
);
rc
=
llc_ui_wait_for_disc
(
sk
,
sk
->
rcvtimeo
);
/* Wake up anyone sleeping in poll */
sk
->
state_change
(
sk
);
out:
...
...
@@ -739,7 +568,7 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
int
addrlen
,
int
flags
)
{
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
net_device
*
dev
;
int
rc
=
-
EINVAL
;
...
...
@@ -757,14 +586,15 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
if
(
rc
)
goto
out
;
}
if
(
!
llc
_ui
->
dev
)
{
if
(
!
llc
->
dev
)
{
rtnl_lock
();
dev
=
dev_getbyhwaddr
(
addr
->
sllc_arphrd
,
addr
->
sllc_smac
);
rtnl_unlock
();
if
(
!
dev
)
goto
out
;
llc
->
dev
=
dev
;
}
else
dev
=
llc
_ui
->
dev
;
dev
=
llc
->
dev
;
if
(
sk
->
type
!=
SOCK_STREAM
)
goto
out
;
rc
=
-
EALREADY
;
...
...
@@ -772,14 +602,18 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
goto
out
;
sock
->
state
=
SS_CONNECTING
;
sk
->
state
=
TCP_SYN_SENT
;
llc_ui
->
link
=
llc_ui_next_link_no
(
llc_ui
->
sap
->
laddr
.
lsap
);
rc
=
llc_ui_send_conn
(
sk
,
llc_ui
->
sap
,
addr
,
dev
,
llc_ui
->
link
);
llc
->
link
=
llc_ui_next_link_no
(
llc
->
sap
->
laddr
.
lsap
);
rc
=
llc_establish_connection
(
sk
,
dev
->
dev_addr
,
addr
->
sllc_dmac
,
addr
->
sllc_dsap
);
if
(
rc
)
{
dprintk
(
"%s: llc_ui_send_conn failed :-(
\n
"
,
__FUNCTION__
);
sock
->
state
=
SS_UNCONNECTED
;
sk
->
state
=
TCP_CLOSE
;
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:
release_sock
(
sk
);
return
rc
;
...
...
@@ -802,7 +636,7 @@ static int llc_ui_listen(struct socket *sock, int backlog)
if
(
sock
->
state
!=
SS_UNCONNECTED
)
goto
out
;
rc
=
-
EOPNOTSUPP
;
if
(
sk
->
type
!=
SOCK_STREAM
&&
sk
->
type
!=
SOCK_SEQPACKET
)
if
(
sk
->
type
!=
SOCK_STREAM
)
goto
out
;
rc
=
-
EAGAIN
;
if
(
sk
->
zapped
)
...
...
@@ -810,8 +644,6 @@ static int llc_ui_listen(struct socket *sock, int backlog)
rc
=
0
;
if
(
!
(
unsigned
)
backlog
)
/* BSDism */
backlog
=
1
;
if
((
unsigned
)
backlog
>
SOMAXCONN
)
backlog
=
SOMAXCONN
;
sk
->
max_ack_backlog
=
backlog
;
if
(
sk
->
state
!=
TCP_LISTEN
)
{
sk
->
ack_backlog
=
0
;
...
...
@@ -823,18 +655,43 @@ static int llc_ui_listen(struct socket *sock, int backlog)
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
);
int
rc
,
timeout
=
seconds
*
HZ
;
int
rc
;
add_wait_queue_exclusive
(
sk
->
sleep
,
&
wait
);
for
(;;)
{
__set_current_state
(
TASK_INTERRUPTIBLE
);
rc
=
-
ERESTARTSYS
;
if
(
signal_pending
(
current
))
break
;
rc
=
-
EAGAIN
;
if
(
!
timeout
)
break
;
rc
=
0
;
if
(
sk
->
state
!=
TCP_CLOSE
)
if
(
sk
->
state
!=
TCP_CLOSE
)
{
release_sock
(
sk
);
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
;
rc
=
-
ERESTARTSYS
;
if
(
signal_pending
(
current
))
...
...
@@ -842,31 +699,60 @@ static int llc_ui_wait_for_disc(struct sock *sk, int seconds)
rc
=
-
EAGAIN
;
if
(
!
timeout
)
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
);
remove_wait_queue
(
sk
->
sleep
,
&
wait
);
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
);
int
rc
,
timeout
=
seconds
*
HZ
;
int
rc
=
0
;
add_wait_queue_exclusive
(
sk
->
sleep
,
&
wait
);
for
(;;)
{
__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
;
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
if
(
skb_queue_empty
(
&
sk
->
receive_queue
))
{
release_sock
(
sk
);
timeout
=
schedule_timeout
(
timeout
);
if
(
sk
->
state
==
TCP_ESTABLISHED
)
{
if
(
!
llc_ui
->
core_sk
)
rc
=
-
EAGAIN
;
lock_sock
(
sk
);
}
else
break
;
}
rc
=
-
EAGAIN
;
if
(
sk
->
state
==
TCP_CLOSE
)
__set_current_state
(
TASK_RUNNING
);
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
;
rc
=
-
ERESTARTSYS
;
if
(
signal_pending
(
current
))
...
...
@@ -874,6 +760,13 @@ static int llc_ui_wait_for_conn(struct sock *sk, int seconds)
rc
=
-
EAGAIN
;
if
(
!
timeout
)
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
);
remove_wait_queue
(
sk
->
sleep
,
&
wait
);
...
...
@@ -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
)
{
struct
sock
*
sk
=
sock
->
sk
,
*
newsk
;
struct
llc_ui_opt
*
llc_ui
,
*
newllc_ui
;
struct
llc_opt
*
newllc_core
;
struct
llc_opt
*
llc
,
*
newllc
;
struct
sk_buff
*
skb
;
int
rc
=
-
EOPNOTSUPP
;
dprintk
(
"%s: accepting on %02X
\n
"
,
__FUNCTION__
,
llc_sk
(
sk
)
->
addr
.
sllc_ssap
);
lock_sock
(
sk
);
if
(
sk
->
type
!=
SOCK_S
EQPACKET
&&
sk
->
type
!=
SOCK_S
TREAM
)
if
(
sk
->
type
!=
SOCK_STREAM
)
goto
out
;
rc
=
-
EINVAL
;
if
(
sock
->
state
!=
SS_UNCONNECTED
||
sk
->
state
!=
TCP_LISTEN
)
goto
out
;
/* wait for a connection to arrive. */
do
{
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
))
rc
=
llc_ui_wait_for_data
(
sk
,
sk
->
rcvtimeo
);
if
(
rc
)
goto
out
;
}
}
while
(
!
skb
);
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
;
/* attach connection to a new socket. */
rc
=
llc_ui_create
(
newsock
,
sk
->
protocol
);
if
(
rc
)
if
(
!
skb
->
sk
)
goto
frees
;
rc
=
0
;
newsk
=
newsock
->
sk
;
newsk
=
skb
->
sk
;
/* attach connection to a new socket. */
llc_ui_sk_init
(
newsock
,
newsk
);
newsk
->
pair
=
NULL
;
newsk
->
socket
=
newsock
;
newsk
->
sleep
=
&
newsock
->
wait
;
newsk
->
zapped
=
0
;
newsk
->
state
=
TCP_ESTABLISHED
;
newsock
->
state
=
SS_CONNECTED
;
llc_ui
=
llc_ui_sk
(
sk
);
newllc_ui
=
llc_ui_sk
(
newsk
);
newllc_ui
->
sap
=
llc_ui
->
sap
;
newllc_ui
->
dev
=
llc_ui
->
dev
;
newllc_ui
->
core_sk
=
skb
->
sk
;
newllc_core
=
llc_sk
(
newllc_ui
->
core_sk
);
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
;
llc
=
llc_sk
(
sk
);
newllc
=
llc_sk
(
newsk
);
memcpy
(
&
newllc
->
addr
,
&
llc
->
addr
,
sizeof
(
newllc
->
addr
));
memcpy
(
newllc
->
addr
.
sllc_dmac
,
newllc
->
daddr
.
mac
,
IFHWADDRLEN
);
newllc
->
addr
.
sllc_dsap
=
newllc
->
daddr
.
lsap
;
newllc
->
link
=
llc_ui_next_link_no
(
newllc
->
laddr
.
lsap
);
/* put original socket back into a clean listen state. */
sk
->
state
=
TCP_LISTEN
;
sk
->
ack_backlog
--
;
llc_ui_insert_socket
(
newsk
);
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:
kfree_skb
(
skb
);
out:
...
...
@@ -973,12 +851,21 @@ static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, int size,
struct
sock
*
sk
=
sock
->
sk
;
struct
sockaddr_llc
*
uaddr
=
(
struct
sockaddr_llc
*
)
msg
->
msg_name
;
struct
sk_buff
*
skb
;
int
rc
=
-
ENOMEM
,
copied
=
0
;
int
rc
=
-
ENOMEM
,
copied
=
0
,
timeout
;
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
);
skb
=
skb_recv_datagram
(
sk
,
flags
,
noblock
,
&
rc
);
if
(
!
skb
)
timeout
=
sock_rcvtimeo
(
sk
,
noblock
);
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
;
copied
=
skb
->
len
;
if
(
copied
>
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
));
msg
->
msg_namelen
=
sizeof
(
*
uaddr
);
dgram_free:
skb_free_datagram
(
sk
,
skb
);
/* Free the datagram. */
kfree_skb
(
skb
);
out:
release_sock
(
sk
);
return
rc
?
:
copied
;
...
...
@@ -1012,24 +899,23 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
struct
scm_cookie
*
scm
)
{
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
;
int
flags
=
msg
->
msg_flags
;
int
noblock
=
flags
&
MSG_DONTWAIT
;
struct
net_device
*
dev
;
struct
sk_buff
*
skb
;
int
rc
=
-
E
OPNOTSUPP
,
size
=
0
;
int
rc
=
-
E
INVAL
,
size
=
0
;
dprintk
(
"%s: sending from %02X to %02X
\n
"
,
__FUNCTION__
,
llc
->
laddr
.
lsap
,
llc
->
daddr
.
lsap
);
lock_sock
(
sk
);
if
(
flags
&
~
MSG_DONTWAIT
)
goto
release
;
rc
=
-
EINVAL
;
if
(
addr
)
{
if
(
msg
->
msg_namelen
<
sizeof
(
*
addr
))
goto
release
;
}
else
{
if
(
llc_ui_addr_null
(
&
llc
_ui
->
addr
))
if
(
llc_ui_addr_null
(
&
llc
->
addr
))
goto
release
;
addr
=
&
llc
_ui
->
addr
;
addr
=
&
llc
->
addr
;
}
/* must bind connection to sap if user hasn't done it. */
if
(
sk
->
zapped
)
{
...
...
@@ -1038,7 +924,7 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
if
(
rc
)
goto
release
;
}
if
(
!
llc
_ui
->
dev
)
{
if
(
!
llc
->
dev
)
{
rtnl_lock
();
dev
=
dev_getbyhwaddr
(
addr
->
sllc_arphrd
,
addr
->
sllc_smac
);
rtnl_unlock
();
...
...
@@ -1046,12 +932,12 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len,
if
(
!
dev
)
goto
release
;
}
else
dev
=
llc
_ui
->
dev
;
dev
=
llc
->
dev
;
size
=
dev
->
hard_header_len
+
len
+
llc_ui_header_len
(
sk
,
addr
);
rc
=
-
EMSGSIZE
;
if
(
size
>
dev
->
mtu
)
goto
release
;
skb
=
sock_alloc_send_skb
(
sk
,
size
,
flags
&
MSG_DONTWAIT
,
&
rc
);
skb
=
sock_alloc_send_skb
(
sk
,
size
,
noblock
,
&
rc
);
if
(
!
skb
)
goto
release
;
skb
->
sk
=
sk
;
...
...
@@ -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
));
rc
=
memcpy_fromiovec
(
skb_put
(
skb
,
len
),
msg
->
msg_iov
,
len
);
if
(
rc
)
goto
release
;
goto
out
;
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
;
}
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
;
}
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
;
}
rc
=
-
ENOPROTOOPT
;
if
(
!
(
sk
->
type
==
SOCK_STREAM
&&
!
addr
->
sllc_ua
))
goto
out
;
rc
=
-
ENOTCONN
;
if
(
!
llc_ui
->
core_sk
)
goto
out
;
rc
=
llc_ui_send_data
(
llc_ui
->
sap
,
sk
,
skb
,
addr
);
rc
=
llc_ui_send_data
(
sk
,
skb
,
addr
,
noblock
);
if
(
rc
)
dprintk
(
"%s: llc_ui_send_data failed: %d
\n
"
,
__FUNCTION__
,
rc
);
out:
if
(
rc
)
skb_free_datagram
(
sk
,
skb
);
kfree_skb
(
skb
);
release:
if
(
rc
)
dprintk
(
"%s: failed sending from %02X to %02X: %d
\n
"
,
__FUNCTION__
,
llc
->
laddr
.
lsap
,
llc
->
daddr
.
lsap
,
rc
);
release_sock
(
sk
);
return
rc
?
:
len
;
}
...
...
@@ -1101,7 +989,7 @@ static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr,
{
struct
sockaddr_llc
sllc
;
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
;
lock_sock
(
sk
);
...
...
@@ -1113,20 +1001,19 @@ static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr,
rc
=
-
ENOTCONN
;
if
(
sk
->
state
!=
TCP_ESTABLISHED
)
goto
out
;
if
(
llc_ui
->
dev
)
sllc
.
sllc_arphrd
=
llc_ui
->
dev
->
type
;
sllc
.
sllc_dsap
=
llc_sk
(
llc_ui
->
core_sk
)
->
daddr
.
lsap
;
memcpy
(
&
sllc
.
sllc_dmac
,
&
llc_sk
(
llc_ui
->
core_sk
)
->
daddr
.
mac
,
IFHWADDRLEN
);
if
(
llc
->
dev
)
sllc
.
sllc_arphrd
=
llc
->
dev
->
type
;
sllc
.
sllc_dsap
=
llc
->
daddr
.
lsap
;
memcpy
(
&
sllc
.
sllc_dmac
,
&
llc
->
daddr
.
mac
,
IFHWADDRLEN
);
}
else
{
rc
=
-
EINVAL
;
if
(
!
llc
_ui
->
sap
)
if
(
!
llc
->
sap
)
goto
out
;
sllc
.
sllc_ssap
=
llc
_ui
->
sap
->
laddr
.
lsap
;
sllc
.
sllc_ssap
=
llc
->
sap
->
laddr
.
lsap
;
if
(
llc
_ui
->
dev
)
{
sllc
.
sllc_arphrd
=
llc
_ui
->
dev
->
type
;
memcpy
(
&
sllc
.
sllc_smac
,
&
llc
_ui
->
dev
->
dev_addr
,
if
(
llc
->
dev
)
{
sllc
.
sllc_arphrd
=
llc
->
dev
->
type
;
memcpy
(
&
sllc
.
sllc_smac
,
&
llc
->
dev
->
dev_addr
,
IFHWADDRLEN
);
}
}
...
...
@@ -1166,61 +1053,56 @@ static int llc_ui_setsockopt(struct socket *sock, int level, int optname,
char
*
optval
,
int
optlen
)
{
struct
sock
*
sk
=
sock
->
sk
;
struct
llc_ui_opt
*
llc_ui
=
llc_ui_sk
(
sk
);
struct
llc_opt
*
llc_core
;
struct
llc_opt
*
llc
=
llc_sk
(
sk
);
int
rc
=
-
EINVAL
,
opt
;
lock_sock
(
sk
);
if
(
level
!=
SOL_LLC
||
optlen
!=
sizeof
(
int
))
goto
out
;
rc
=
-
ENOTCONN
;
if
(
!
llc_ui
->
core_sk
)
goto
out
;
rc
=
get_user
(
opt
,
(
int
*
)
optval
);
if
(
rc
)
goto
out
;
rc
=
-
EINVAL
;
llc_core
=
llc_sk
(
llc_ui
->
core_sk
);
switch
(
optname
)
{
case
LLC_OPT_RETRY
:
if
(
opt
>
LLC_OPT_MAX_RETRY
)
goto
out
;
llc
_core
->
n2
=
opt
;
llc
->
n2
=
opt
;
break
;
case
LLC_OPT_SIZE
:
if
(
opt
>
LLC_OPT_MAX_SIZE
)
goto
out
;
llc
_core
->
n1
=
opt
;
llc
->
n1
=
opt
;
break
;
case
LLC_OPT_ACK_TMR_EXP
:
if
(
opt
>
LLC_OPT_MAX_ACK_TMR_EXP
)
goto
out
;
llc
_core
->
ack_timer
.
expire
=
opt
;
llc
->
ack_timer
.
expire
=
opt
;
break
;
case
LLC_OPT_P_TMR_EXP
:
if
(
opt
>
LLC_OPT_MAX_P_TMR_EXP
)
goto
out
;
llc
_core
->
pf_cycle_timer
.
expire
=
opt
;
llc
->
pf_cycle_timer
.
expire
=
opt
;
break
;
case
LLC_OPT_REJ_TMR_EXP
:
if
(
opt
>
LLC_OPT_MAX_REJ_TMR_EXP
)
goto
out
;
llc
_core
->
rej_sent_timer
.
expire
=
opt
;
llc
->
rej_sent_timer
.
expire
=
opt
;
break
;
case
LLC_OPT_BUSY_TMR_EXP
:
if
(
opt
>
LLC_OPT_MAX_BUSY_TMR_EXP
)
goto
out
;
llc
_core
->
busy_state_timer
.
expire
=
opt
;
llc
->
busy_state_timer
.
expire
=
opt
;
break
;
case
LLC_OPT_TX_WIN
:
if
(
opt
>
LLC_OPT_MAX_WIN
)
goto
out
;
llc
_core
->
k
=
opt
;
llc
->
k
=
opt
;
break
;
case
LLC_OPT_RX_WIN
:
if
(
opt
>
LLC_OPT_MAX_WIN
)
goto
out
;
llc
_core
->
rw
=
opt
;
llc
->
rw
=
opt
;
break
;
default:
rc
=
-
ENOPROTOOPT
;
...
...
@@ -1246,40 +1128,35 @@ static int llc_ui_getsockopt(struct socket *sock, int level, int optname,
char
*
optval
,
int
*
optlen
)
{
struct
sock
*
sk
=
sock
->
sk
;
struct
llc_ui_opt
*
llc_ui
=
llc_ui_sk
(
sk
);
struct
llc_opt
*
llc_core
;
struct
llc_opt
*
llc
=
llc_sk
(
sk
);
int
val
=
0
,
len
=
0
,
rc
=
-
EINVAL
;
lock_sock
(
sk
);
if
(
level
!=
SOL_LLC
)
goto
out
;
rc
=
-
ENOTCONN
;
if
(
!
llc_ui
->
core_sk
)
goto
out
;
rc
=
get_user
(
len
,
optlen
);
if
(
rc
)
goto
out
;
rc
=
-
EINVAL
;
if
(
len
!=
sizeof
(
int
))
goto
out
;
llc_core
=
llc_sk
(
llc_ui
->
core_sk
);
switch
(
optname
)
{
case
LLC_OPT_RETRY
:
val
=
llc
_core
->
n2
;
break
;
val
=
llc
->
n2
;
break
;
case
LLC_OPT_SIZE
:
val
=
llc
_core
->
n1
;
break
;
val
=
llc
->
n1
;
break
;
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
:
val
=
llc
_core
->
pf_cycle_timer
.
expire
;
break
;
val
=
llc
->
pf_cycle_timer
.
expire
;
break
;
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
:
val
=
llc
_core
->
busy_state_timer
.
expire
;
break
;
val
=
llc
->
busy_state_timer
.
expire
;
break
;
case
LLC_OPT_TX_WIN
:
val
=
llc
_core
->
k
;
break
;
val
=
llc
->
k
;
break
;
case
LLC_OPT_RX_WIN
:
val
=
llc
_core
->
rw
;
break
;
val
=
llc
->
rw
;
break
;
default:
rc
=
-
ENOPROTOOPT
;
goto
out
;
...
...
@@ -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
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
,
&
prim_data
->
saddr
,
skb
->
dev
);
if
(
!
sk
)
...
...
@@ -1310,15 +1187,15 @@ static void llc_ui_ind_test(struct llc_prim_if_block *prim)
if
(
sk
->
state
==
TCP_LISTEN
)
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
=
1
;
llc_ui
->
sllc_xid
=
0
;
llc_ui
->
sllc_ua
=
0
;
llc_ui
->
sllc_dsap
=
prim_data
->
daddr
.
lsap
;
memcpy
(
llc_ui
->
sllc_dmac
,
prim_data
->
daddr
.
mac
,
IFHWADDRLEN
);
llc_ui
->
sllc_ssap
=
prim_data
->
saddr
.
lsap
;
memcpy
(
llc_ui
->
sllc_smac
,
prim_data
->
saddr
.
mac
,
IFHWADDRLEN
);
addr
->
sllc_family
=
AF_LLC
;
addr
->
sllc_arphrd
=
skb
->
dev
->
type
;
addr
->
sllc_test
=
1
;
addr
->
sllc_xid
=
0
;
addr
->
sllc_ua
=
0
;
addr
->
sllc_dsap
=
prim_data
->
daddr
.
lsap
;
memcpy
(
addr
->
sllc_dmac
,
prim_data
->
daddr
.
mac
,
IFHWADDRLEN
);
addr
->
sllc_ssap
=
prim_data
->
saddr
.
lsap
;
memcpy
(
addr
->
sllc_smac
,
prim_data
->
saddr
.
mac
,
IFHWADDRLEN
);
/* queue skb to the user. */
if
(
sock_queue_rcv_skb
(
sk
,
skb
))
kfree_skb
(
skb
);
...
...
@@ -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
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
,
&
prim_data
->
saddr
,
skb
->
dev
);
if
(
!
sk
)
...
...
@@ -1345,15 +1222,15 @@ static void llc_ui_ind_xid(struct llc_prim_if_block *prim)
if
(
sk
->
state
==
TCP_LISTEN
)
goto
out_put
;
/* save primitive for use by the user. */
llc_ui
->
sllc_family
=
AF_LLC
;
llc_ui
->
sllc_arphrd
=
0
;
llc_ui
->
sllc_test
=
0
;
llc_ui
->
sllc_xid
=
1
;
llc_ui
->
sllc_ua
=
0
;
llc_ui
->
sllc_dsap
=
prim_data
->
daddr
.
lsap
;
memcpy
(
llc_ui
->
sllc_dmac
,
prim_data
->
daddr
.
mac
,
IFHWADDRLEN
);
llc_ui
->
sllc_ssap
=
prim_data
->
saddr
.
lsap
;
memcpy
(
llc_ui
->
sllc_smac
,
prim_data
->
saddr
.
mac
,
IFHWADDRLEN
);
addr
->
sllc_family
=
AF_LLC
;
addr
->
sllc_arphrd
=
0
;
addr
->
sllc_test
=
0
;
addr
->
sllc_xid
=
1
;
addr
->
sllc_ua
=
0
;
addr
->
sllc_dsap
=
prim_data
->
daddr
.
lsap
;
memcpy
(
addr
->
sllc_dmac
,
prim_data
->
daddr
.
mac
,
IFHWADDRLEN
);
addr
->
sllc_ssap
=
prim_data
->
saddr
.
lsap
;
memcpy
(
addr
->
sllc_smac
,
prim_data
->
saddr
.
mac
,
IFHWADDRLEN
);
/* queue skb to the user. */
if
(
sock_queue_rcv_skb
(
sk
,
skb
))
kfree_skb
(
skb
);
...
...
@@ -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
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
,
&
prim_data
->
saddr
,
skb
->
dev
);
if
(
!
sk
)
...
...
@@ -1380,88 +1257,15 @@ static void llc_ui_ind_dataunit(struct llc_prim_if_block *prim)
if
(
sk
->
state
==
TCP_LISTEN
)
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
=
1
;
llc_ui
->
sllc_dsap
=
prim_data
->
daddr
.
lsap
;
memcpy
(
llc_ui
->
sllc_dmac
,
prim_data
->
daddr
.
mac
,
IFHWADDRLEN
);
llc_ui
->
sllc_ssap
=
prim_data
->
saddr
.
lsap
;
memcpy
(
llc_ui
->
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
);
addr
->
sllc_family
=
AF_LLC
;
addr
->
sllc_arphrd
=
skb
->
dev
->
type
;
addr
->
sllc_test
=
0
;
addr
->
sllc_xid
=
0
;
addr
->
sllc_ua
=
1
;
addr
->
sllc_dsap
=
prim_data
->
daddr
.
lsap
;
memcpy
(
addr
->
sllc_dmac
,
prim_data
->
daddr
.
mac
,
IFHWADDRLEN
);
addr
->
sllc_ssap
=
prim_data
->
saddr
.
lsap
;
memcpy
(
addr
->
sllc_smac
,
prim_data
->
saddr
.
mac
,
IFHWADDRLEN
);
/* queue skb to the user. */
if
(
sock_queue_rcv_skb
(
sk
,
skb
))
kfree_skb
(
skb
);
...
...
@@ -1470,35 +1274,6 @@ static void llc_ui_ind_data(struct llc_prim_if_block *prim)
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.
* @prim: Primitive block provided by the llc layer.
...
...
@@ -1517,91 +1292,23 @@ static int llc_ui_indicate(struct llc_prim_if_block *prim)
case
LLC_DATAUNIT_PRIM
:
llc_ui_ind_dataunit
(
prim
);
break
;
case
LLC_CONN_PRIM
:
llc_ui_ind_conn
(
prim
);
break
;
dprintk
(
"%s: shouldn't happen, LLC_CONN_PRIM "
"is gone for ->ind()...
\n
"
,
__FUNCTION__
);
break
;
case
LLC_DATA_PRIM
:
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
:
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_FLOWCONTROL_PRIM
:
default:
break
;
}
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
* @prim: Primitive block provided by the llc layer.
...
...
@@ -1614,14 +1321,20 @@ static int llc_ui_confirm(struct llc_prim_if_block *prim)
{
switch
(
prim
->
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
:
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
:
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
;
default:
printk
(
KERN_ERR
"%s:
unknown prim
%d
\n
"
,
__FUNCTION__
,
printk
(
KERN_ERR
"%s:
prim not supported
%d
\n
"
,
__FUNCTION__
,
prim
->
prim
);
break
;
}
...
...
@@ -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
begin
=
0
;
struct
sock
*
s
;
int
len
=
sprintf
(
buffer
,
"S
ocketID SKt Mc local_mac_sap
\t
"
"remote_mac_sap
\t
tx_queue rx_queue st uid "
"link
_no
\n
"
);
int
len
=
sprintf
(
buffer
,
"S
Kt Mc local_mac_sap
"
"remote_mac_sap
tx_queue rx_queue st uid "
"link
\n
"
);
/* Output the LLC socket data for the /proc filesystem */
read_lock_bh
(
&
llc_ui_sockets_lock
);
for
(
s
=
llc_ui_sockets
;
s
;
s
=
s
->
next
)
{
struct
llc_
ui_opt
*
llc_ui
=
llc_ui
_sk
(
s
);
len
+=
sprintf
(
buffer
+
len
,
"%p %02X %02X "
,
s
,
s
->
type
,
!
llc_ui_mac_null
(
llc_ui
->
addr
.
sllc_mmac
));
if
(
llc_ui
->
sap
)
{
if
(
llc_ui
->
dev
&&
llc_ui_mac_null
(
llc_ui
->
addr
.
sllc_mmac
))
struct
llc_
opt
*
llc
=
llc
_sk
(
s
);
len
+=
sprintf
(
buffer
+
len
,
"%2X %2X "
,
s
->
type
,
!
llc_mac_null
(
llc
->
addr
.
sllc_mmac
));
if
(
llc
->
sap
)
{
if
(
llc
->
dev
&&
llc_mac_null
(
llc
->
addr
.
sllc_mmac
))
llc_ui_format_mac
(
buffer
+
len
,
llc
_ui
->
dev
->
dev_addr
);
llc
->
dev
->
dev_addr
);
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
->
addr
.
sllc_mmac
);
llc
->
addr
.
sllc_mmac
);
else
sprintf
(
buffer
+
len
,
"00:00:00:00:00:00"
);
}
len
+=
MAC_FORMATTED_SIZE
;
len
+=
sprintf
(
buffer
+
len
,
"@%02X "
,
llc
_ui
->
sap
->
laddr
.
lsap
);
llc
->
sap
->
laddr
.
lsap
);
}
else
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
+=
sprintf
(
buffer
+
len
,
"@%02X %
08d:%08d %0
2d %-3d "
,
llc
_ui
->
addr
.
sllc_dsap
,
"@%02X %
8d %8d %
2d %-3d "
,
llc
->
addr
.
sllc_dsap
,
atomic_read
(
&
s
->
wmem_alloc
),
atomic_read
(
&
s
->
rmem_alloc
),
s
->
state
,
SOCK_INODE
(
s
->
socket
)
->
i_uid
);
if
(
llc_ui
->
core_sk
)
len
+=
sprintf
(
buffer
+
len
,
"%-7d
\n
"
,
llc_sk
(
llc_ui
->
core_sk
)
->
link
);
else
len
+=
sprintf
(
buffer
+
len
,
"no_link
\n
"
);
len
+=
sprintf
(
buffer
+
len
,
"%-4d
\n
"
,
llc
->
link
);
/* Are we still dumping unwanted data then discard the record */
pos
=
begin
+
len
;
...
...
@@ -1741,7 +1450,7 @@ static struct proto_ops SOCKOPS_WRAPPED(llc_ui_ops) = {
SOCKOPS_WRAP
(
llc_ui
,
PF_LLC
);
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
)
{
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment