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
d038b8c5
Commit
d038b8c5
authored
Sep 13, 2002
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge master.kernel.org:/home/davem/BK/net-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
parents
d1a75a97
1a2c129e
Changes
27
Hide whitespace changes
Inline
Side-by-side
Showing
27 changed files
with
2054 additions
and
1658 deletions
+2054
-1658
drivers/net/tg3.c
drivers/net/tg3.c
+939
-157
drivers/net/tg3.h
drivers/net/tg3.h
+47
-12
drivers/pci/pci.ids
drivers/pci/pci.ids
+1
-0
include/linux/llc.h
include/linux/llc.h
+0
-11
include/linux/pci_ids.h
include/linux/pci_ids.h
+1
-0
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
-3
net/8021q/vlan.c
net/8021q/vlan.c
+1
-1
net/core/dev.c
net/core/dev.c
+6
-4
net/ipv4/ip_options.c
net/ipv4/ip_options.c
+1
-1
net/ipv4/tcp_input.c
net/ipv4/tcp_input.c
+30
-5
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.
drivers/net/tg3.c
View file @
d038b8c5
...
...
@@ -48,12 +48,19 @@
#define TG3_VLAN_TAG_USED 0
#endif
#ifdef NETIF_F_TSO
/* XXX some bug in tso firmware hangs tx cpu, disabled until fixed */
#define TG3_DO_TSO 0
#else
#define TG3_DO_TSO 0
#endif
#include "tg3.h"
#define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "1.
0
"
#define DRV_MODULE_RELDATE "
Jul 19
, 2002"
#define DRV_MODULE_VERSION "1.
1
"
#define DRV_MODULE_RELDATE "
Aug 30
, 2002"
#define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0
...
...
@@ -142,6 +149,8 @@ static struct pci_device_id tg3_pci_tbl[] __devinitdata = {
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
0UL
},
{
PCI_VENDOR_ID_BROADCOM
,
PCI_DEVICE_ID_TIGON3_5703
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
0UL
},
{
PCI_VENDOR_ID_BROADCOM
,
PCI_DEVICE_ID_TIGON3_5704
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
0UL
},
{
PCI_VENDOR_ID_BROADCOM
,
PCI_DEVICE_ID_TIGON3_5702FE
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
0UL
},
{
PCI_VENDOR_ID_BROADCOM
,
PCI_DEVICE_ID_TIGON3_5702X
,
...
...
@@ -212,6 +221,7 @@ static void tg3_disable_ints(struct tg3 *tp)
tw32
(
TG3PCI_MISC_HOST_CTRL
,
(
tp
->
misc_host_ctrl
|
MISC_HOST_CTRL_MASK_PCI_INT
));
tw32_mailbox
(
MAILBOX_INTERRUPT_0
+
TG3_64BIT_REG_LOW
,
0x00000001
);
tr32
(
MAILBOX_INTERRUPT_0
+
TG3_64BIT_REG_LOW
);
}
static
void
tg3_enable_ints
(
struct
tg3
*
tp
)
...
...
@@ -220,9 +230,11 @@ static void tg3_enable_ints(struct tg3 *tp)
(
tp
->
misc_host_ctrl
&
~
MISC_HOST_CTRL_MASK_PCI_INT
));
tw32_mailbox
(
MAILBOX_INTERRUPT_0
+
TG3_64BIT_REG_LOW
,
0x00000000
);
if
(
tp
->
hw_status
->
status
&
SD_STATUS_UPDATED
)
if
(
tp
->
hw_status
->
status
&
SD_STATUS_UPDATED
)
{
tw32
(
GRC_LOCAL_CTRL
,
tp
->
grc_local_ctrl
|
GRC_LCLCTRL_SETINT
);
}
tr32
(
MAILBOX_INTERRUPT_0
+
TG3_64BIT_REG_LOW
);
}
#define PHY_BUSY_LOOPS 5000
...
...
@@ -235,6 +247,7 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
if
((
tp
->
mi_mode
&
MAC_MI_MODE_AUTO_POLL
)
!=
0
)
{
tw32
(
MAC_MI_MODE
,
(
tp
->
mi_mode
&
~
MAC_MI_MODE_AUTO_POLL
));
tr32
(
MAC_MI_MODE
);
udelay
(
40
);
}
...
...
@@ -247,9 +260,11 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
frame_val
|=
(
MI_COM_CMD_READ
|
MI_COM_START
);
tw32
(
MAC_MI_COM
,
frame_val
);
tr32
(
MAC_MI_COM
);
loops
=
PHY_BUSY_LOOPS
;
while
(
loops
--
>
0
)
{
udelay
(
10
);
frame_val
=
tr32
(
MAC_MI_COM
);
if
((
frame_val
&
MI_COM_BUSY
)
==
0
)
{
...
...
@@ -257,7 +272,6 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
frame_val
=
tr32
(
MAC_MI_COM
);
break
;
}
udelay
(
10
);
}
ret
=
-
EBUSY
;
...
...
@@ -268,6 +282,7 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val)
if
((
tp
->
mi_mode
&
MAC_MI_MODE_AUTO_POLL
)
!=
0
)
{
tw32
(
MAC_MI_MODE
,
tp
->
mi_mode
);
tr32
(
MAC_MI_MODE
);
udelay
(
40
);
}
...
...
@@ -282,6 +297,7 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
if
((
tp
->
mi_mode
&
MAC_MI_MODE_AUTO_POLL
)
!=
0
)
{
tw32
(
MAC_MI_MODE
,
(
tp
->
mi_mode
&
~
MAC_MI_MODE_AUTO_POLL
));
tr32
(
MAC_MI_MODE
);
udelay
(
40
);
}
...
...
@@ -293,16 +309,17 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
frame_val
|=
(
MI_COM_CMD_WRITE
|
MI_COM_START
);
tw32
(
MAC_MI_COM
,
frame_val
);
tr32
(
MAC_MI_COM
);
loops
=
PHY_BUSY_LOOPS
;
while
(
loops
--
>
0
)
{
udelay
(
10
);
frame_val
=
tr32
(
MAC_MI_COM
);
if
((
frame_val
&
MI_COM_BUSY
)
==
0
)
{
udelay
(
5
);
frame_val
=
tr32
(
MAC_MI_COM
);
break
;
}
udelay
(
10
);
}
ret
=
-
EBUSY
;
...
...
@@ -311,6 +328,7 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val)
if
((
tp
->
mi_mode
&
MAC_MI_MODE_AUTO_POLL
)
!=
0
)
{
tw32
(
MAC_MI_MODE
,
tp
->
mi_mode
);
tr32
(
MAC_MI_MODE
);
udelay
(
40
);
}
...
...
@@ -388,7 +406,9 @@ static int tg3_set_power_state(struct tg3 *tp, int state)
pm
+
PCI_PM_CTRL
,
power_control
);
tw32
(
GRC_LOCAL_CTRL
,
tp
->
grc_local_ctrl
);
tg3_writephy
(
tp
,
MII_TG3_AUX_CTRL
,
0x02
);
tr32
(
GRC_LOCAL_CTRL
);
udelay
(
100
);
return
0
;
case
1
:
...
...
@@ -424,6 +444,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state)
}
tp
->
link_config
.
speed
=
SPEED_10
;
tp
->
link_config
.
duplex
=
DUPLEX_HALF
;
tp
->
link_config
.
autoneg
=
AUTONEG_ENABLE
;
tg3_setup_phy
(
tp
);
...
...
@@ -435,51 +456,108 @@ static int tg3_set_power_state(struct tg3 *tp, int state)
u32
mac_mode
;
tg3_writephy
(
tp
,
MII_TG3_AUX_CTRL
,
0x5a
);
udelay
(
40
);
mac_mode
=
MAC_MODE_PORT_MODE_MII
;
mac_mode
=
MAC_MODE_PORT_MODE_MII
|
MAC_MODE_LINK_POLARITY
;
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
!=
ASIC_REV_5700
||
!
(
tp
->
tg3_flags
&
TG3_FLAG_WOL_SPEED_100MB
))
mac_mode
|=
MAC_MODE_LINK_POLARITY
;
if
(((
power_caps
&
PCI_PM_CAP_PME_D3cold
)
&&
(
tp
->
tg3_flags
&
TG3_FLAG_WOL_ENABLE
)))
mac_mode
|=
MAC_MODE_MAGIC_PKT_ENABLE
;
tw32
(
MAC_MODE
,
mac_mode
);
tr32
(
MAC_MODE
);
udelay
(
40
);
tw32
(
MAC_RX_MODE
,
RX_MODE_ENABLE
);
tr32
(
MAC_RX_MODE
);
udelay
(
10
);
}
if
(
tp
->
tg3_flags
&
TG3_FLAG_WOL_SPEED_100MB
)
{
tw32
(
TG3PCI_CLOCK_CTRL
,
(
CLOCK_CTRL_RXCLK_DISABLE
|
CLOCK_CTRL_TXCLK_DISABLE
|
CLOCK_CTRL_ALTCLK
));
tw32
(
TG3PCI_CLOCK_CTRL
,
(
CLOCK_CTRL_RXCLK_DISABLE
|
CLOCK_CTRL_TXCLK_DISABLE
|
CLOCK_CTRL_44MHZ_CORE
));
tw32
(
TG3PCI_CLOCK_CTRL
,
(
CLOCK_CTRL_RXCLK_DISABLE
|
CLOCK_CTRL_TXCLK_DISABLE
|
CLOCK_CTRL_ALTCLK
|
CLOCK_CTRL_44MHZ_CORE
));
u32
base_val
;
base_val
=
0
;
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5700
||
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5701
)
base_val
|=
(
CLOCK_CTRL_RXCLK_DISABLE
|
CLOCK_CTRL_TXCLK_DISABLE
);
tw32
(
TG3PCI_CLOCK_CTRL
,
base_val
|
CLOCK_CTRL_ALTCLK
);
tr32
(
TG3PCI_CLOCK_CTRL
);
udelay
(
40
);
tw32
(
TG3PCI_CLOCK_CTRL
,
base_val
|
CLOCK_CTRL_ALTCLK
|
CLOCK_CTRL_44MHZ_CORE
);
tr32
(
TG3PCI_CLOCK_CTRL
);
udelay
(
40
);
tw32
(
TG3PCI_CLOCK_CTRL
,
base_val
|
CLOCK_CTRL_44MHZ_CORE
);
tr32
(
TG3PCI_CLOCK_CTRL
);
udelay
(
40
);
}
else
{
tw32
(
TG3PCI_CLOCK_CTRL
,
(
CLOCK_CTRL_RXCLK_DISABLE
|
CLOCK_CTRL_TXCLK_DISABLE
|
CLOCK_CTRL_ALTCLK
|
CLOCK_CTRL_PWRDOWN_PLL133
));
u32
base_val
;
base_val
=
0
;
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5700
||
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5701
)
base_val
|=
(
CLOCK_CTRL_RXCLK_DISABLE
|
CLOCK_CTRL_TXCLK_DISABLE
);
tw32
(
TG3PCI_CLOCK_CTRL
,
base_val
|
CLOCK_CTRL_ALTCLK
|
CLOCK_CTRL_PWRDOWN_PLL133
);
tr32
(
TG3PCI_CLOCK_CTRL
);
udelay
(
40
);
}
udelay
(
40
);
if
((
power_caps
&
PCI_PM_CAP_PME_D3cold
)
&&
if
(
!
(
tp
->
tg3_flags
&
TG3_FLAG_EEPROM_WRITE_PROT
)
&&
(
tp
->
tg3_flags
&
TG3_FLAG_WOL_ENABLE
))
{
/* Move to auxilliary power. */
tw32
(
GRC_LOCAL_CTRL
,
(
GRC_LCLCTRL_GPIO_OE0
|
GRC_LCLCTRL_GPIO_OE1
|
GRC_LCLCTRL_GPIO_OE2
|
GRC_LCLCTRL_GPIO_OUTPUT0
|
GRC_LCLCTRL_GPIO_OUTPUT1
));
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5700
||
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5701
)
{
tw32
(
GRC_LOCAL_CTRL
,
(
GRC_LCLCTRL_GPIO_OE0
|
GRC_LCLCTRL_GPIO_OE1
|
GRC_LCLCTRL_GPIO_OE2
|
GRC_LCLCTRL_GPIO_OUTPUT0
|
GRC_LCLCTRL_GPIO_OUTPUT1
));
tr32
(
GRC_LOCAL_CTRL
);
udelay
(
100
);
}
else
{
tw32
(
GRC_LOCAL_CTRL
,
(
GRC_LCLCTRL_GPIO_OE0
|
GRC_LCLCTRL_GPIO_OE1
|
GRC_LCLCTRL_GPIO_OE2
|
GRC_LCLCTRL_GPIO_OUTPUT1
|
GRC_LCLCTRL_GPIO_OUTPUT2
));
tr32
(
GRC_LOCAL_CTRL
);
udelay
(
100
);
tw32
(
GRC_LOCAL_CTRL
,
(
GRC_LCLCTRL_GPIO_OE0
|
GRC_LCLCTRL_GPIO_OE1
|
GRC_LCLCTRL_GPIO_OE2
|
GRC_LCLCTRL_GPIO_OUTPUT0
|
GRC_LCLCTRL_GPIO_OUTPUT1
|
GRC_LCLCTRL_GPIO_OUTPUT2
));
tr32
(
GRC_LOCAL_CTRL
);
udelay
(
100
);
tw32
(
GRC_LOCAL_CTRL
,
(
GRC_LCLCTRL_GPIO_OE0
|
GRC_LCLCTRL_GPIO_OE1
|
GRC_LCLCTRL_GPIO_OE2
|
GRC_LCLCTRL_GPIO_OUTPUT0
|
GRC_LCLCTRL_GPIO_OUTPUT1
));
tr32
(
GRC_LOCAL_CTRL
);
udelay
(
100
);
}
}
/* Finally, set the new power state. */
...
...
@@ -636,8 +714,9 @@ static int tg3_phy_copper_begin(struct tg3 *tp, int wait_for_link)
new_adv
|=
MII_TG3_CTRL_ADV_1000_HALF
;
if
(
tp
->
link_config
.
advertising
&
ADVERTISED_1000baseT_Full
)
new_adv
|=
MII_TG3_CTRL_ADV_1000_FULL
;
if
(
tp
->
pci_chip_rev_id
==
CHIPREV_ID_5701_A0
||
tp
->
pci_chip_rev_id
==
CHIPREV_ID_5701_B0
)
if
(
!
(
tp
->
tg3_flags
&
TG3_FLAG_10_100_ONLY
)
&&
(
tp
->
pci_chip_rev_id
==
CHIPREV_ID_5701_A0
||
tp
->
pci_chip_rev_id
==
CHIPREV_ID_5701_B0
))
new_adv
|=
(
MII_TG3_CTRL_AS_MASTER
|
MII_TG3_CTRL_ENABLE_AS_MASTER
);
tg3_writephy
(
tp
,
MII_TG3_CTRL
,
new_adv
);
...
...
@@ -787,11 +866,16 @@ static int tg3_setup_copper_phy(struct tg3 *tp)
tw32
(
MAC_STATUS
,
(
MAC_STATUS_SYNC_CHANGED
|
MAC_STATUS_CFG_CHANGED
));
tr32
(
MAC_STATUS
);
udelay
(
40
);
tp
->
mi_mode
=
MAC_MI_MODE_BASE
;
tw32
(
MAC_MI_MODE
,
tp
->
mi_mode
);
tr32
(
MAC_MI_MODE
);
udelay
(
40
);
tg3_writephy
(
tp
,
MII_TG3_AUX_CTRL
,
0x02
);
if
((
tp
->
phy_id
&
PHY_ID_MASK
)
==
PHY_ID_BCM5401
)
{
tg3_readphy
(
tp
,
MII_BMSR
,
&
bmsr
);
tg3_readphy
(
tp
,
MII_BMSR
,
&
bmsr
);
...
...
@@ -968,10 +1052,13 @@ static int tg3_setup_copper_phy(struct tg3 *tp)
tp
->
pci_chip_rev_id
==
CHIPREV_ID_5700_ALTIMA
)
{
tp
->
mi_mode
|=
MAC_MI_MODE_AUTO_POLL
;
tw32
(
MAC_MI_MODE
,
tp
->
mi_mode
);
tr32
(
MAC_MI_MODE
);
udelay
(
40
);
}
tw32
(
MAC_MODE
,
tp
->
mac_mode
);
tr32
(
MAC_MODE
);
udelay
(
40
);
if
(
tp
->
tg3_flags
&
(
TG3_FLAG_USE_LINKCHG_REG
|
...
...
@@ -981,6 +1068,8 @@ static int tg3_setup_copper_phy(struct tg3 *tp)
}
else
{
tw32
(
MAC_EVENT
,
MAC_EVENT_LNKSTATE_CHANGED
);
}
tr32
(
MAC_EVENT
);
udelay
(
40
);
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5700
&&
current_link_up
==
1
&&
...
...
@@ -991,6 +1080,8 @@ static int tg3_setup_copper_phy(struct tg3 *tp)
tw32
(
MAC_STATUS
,
(
MAC_STATUS_SYNC_CHANGED
|
MAC_STATUS_CFG_CHANGED
));
tr32
(
MAC_STATUS
);
udelay
(
40
);
tg3_write_mem
(
tp
,
NIC_SRAM_FIRMWARE_MBOX
,
NIC_SRAM_FIRMWARE_MBOX_MAGIC2
);
...
...
@@ -1152,6 +1243,9 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
tw32
(
MAC_TX_AUTO_NEG
,
0
);
tp
->
mac_mode
|=
MAC_MODE_SEND_CONFIGS
;
tw32
(
MAC_MODE
,
tp
->
mac_mode
);
tr32
(
MAC_MODE
);
udelay
(
40
);
ret
=
ANEG_TIMER_ENAB
;
ap
->
state
=
ANEG_STATE_RESTART
;
...
...
@@ -1175,6 +1269,8 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
tw32
(
MAC_TX_AUTO_NEG
,
ap
->
txconfig
);
tp
->
mac_mode
|=
MAC_MODE_SEND_CONFIGS
;
tw32
(
MAC_MODE
,
tp
->
mac_mode
);
tr32
(
MAC_MODE
);
udelay
(
40
);
ap
->
state
=
ANEG_STATE_ABILITY_DETECT
;
break
;
...
...
@@ -1190,6 +1286,8 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
tw32
(
MAC_TX_AUTO_NEG
,
ap
->
txconfig
);
tp
->
mac_mode
|=
MAC_MODE_SEND_CONFIGS
;
tw32
(
MAC_MODE
,
tp
->
mac_mode
);
tr32
(
MAC_MODE
);
udelay
(
40
);
ap
->
state
=
ANEG_STATE_ACK_DETECT
;
...
...
@@ -1275,6 +1373,8 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp,
ap
->
link_time
=
ap
->
cur_time
;
tp
->
mac_mode
&=
~
MAC_MODE_SEND_CONFIGS
;
tw32
(
MAC_MODE
,
tp
->
mac_mode
);
tr32
(
MAC_MODE
);
udelay
(
40
);
ap
->
state
=
ANEG_STATE_IDLE_DETECT
;
ret
=
ANEG_TIMER_ENAB
;
...
...
@@ -1331,6 +1431,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp)
tp
->
mac_mode
&=
~
(
MAC_MODE_PORT_MODE_MASK
|
MAC_MODE_HALF_DUPLEX
);
tp
->
mac_mode
|=
MAC_MODE_PORT_MODE_TBI
;
tw32
(
MAC_MODE
,
tp
->
mac_mode
);
tr32
(
MAC_MODE
);
udelay
(
40
);
/* Reset when initting first time or we have a link. */
...
...
@@ -1381,6 +1482,8 @@ static int tg3_setup_fiber_phy(struct tg3 *tp)
tw32
(
MAC_EVENT
,
MAC_EVENT_LNKSTATE_CHANGED
);
else
tw32
(
MAC_EVENT
,
0
);
tr32
(
MAC_EVENT
);
udelay
(
40
);
current_link_up
=
0
;
if
(
tr32
(
MAC_STATUS
)
&
MAC_STATUS_PCS_SYNCED
)
{
...
...
@@ -1398,9 +1501,12 @@ static int tg3_setup_fiber_phy(struct tg3 *tp)
tmp
=
tp
->
mac_mode
&
~
MAC_MODE_PORT_MODE_MASK
;
tw32
(
MAC_MODE
,
tmp
|
MAC_MODE_PORT_MODE_GMII
);
udelay
(
20
);
tr32
(
MAC_MODE
);
udelay
(
40
);
tw32
(
MAC_MODE
,
tp
->
mac_mode
|
MAC_MODE_SEND_CONFIGS
);
tr32
(
MAC_MODE
);
udelay
(
40
);
aninfo
.
state
=
ANEG_STATE_UNKNOWN
;
aninfo
.
cur_time
=
0
;
...
...
@@ -1416,6 +1522,8 @@ static int tg3_setup_fiber_phy(struct tg3 *tp)
tp
->
mac_mode
&=
~
MAC_MODE_SEND_CONFIGS
;
tw32
(
MAC_MODE
,
tp
->
mac_mode
);
tr32
(
MAC_MODE
);
udelay
(
40
);
if
(
status
==
ANEG_DONE
&&
(
aninfo
.
flags
&
...
...
@@ -1441,8 +1549,8 @@ static int tg3_setup_fiber_phy(struct tg3 *tp)
tw32
(
MAC_STATUS
,
(
MAC_STATUS_SYNC_CHANGED
|
MAC_STATUS_CFG_CHANGED
));
udelay
(
2
0
);
tr32
(
MAC_STATUS
);
udelay
(
4
0
);
if
((
tr32
(
MAC_STATUS
)
&
(
MAC_STATUS_SYNC_CHANGED
|
MAC_STATUS_CFG_CHANGED
))
==
0
)
...
...
@@ -1460,6 +1568,8 @@ static int tg3_setup_fiber_phy(struct tg3 *tp)
tp
->
mac_mode
&=
~
MAC_MODE_LINK_POLARITY
;
tw32
(
MAC_MODE
,
tp
->
mac_mode
);
tr32
(
MAC_MODE
);
udelay
(
40
);
tp
->
hw_status
->
status
=
(
SD_STATUS_UPDATED
|
...
...
@@ -1470,8 +1580,8 @@ static int tg3_setup_fiber_phy(struct tg3 *tp)
tw32
(
MAC_STATUS
,
(
MAC_STATUS_SYNC_CHANGED
|
MAC_STATUS_CFG_CHANGED
));
udelay
(
2
0
);
tr32
(
MAC_STATUS
);
udelay
(
4
0
);
if
((
tr32
(
MAC_STATUS
)
&
(
MAC_STATUS_SYNC_CHANGED
|
MAC_STATUS_CFG_CHANGED
))
==
0
)
...
...
@@ -1507,9 +1617,12 @@ static int tg3_setup_fiber_phy(struct tg3 *tp)
if
((
tr32
(
MAC_STATUS
)
&
MAC_STATUS_PCS_SYNCED
)
==
0
)
{
tw32
(
MAC_MODE
,
tp
->
mac_mode
|
MAC_MODE_LINK_POLARITY
);
tr32
(
MAC_MODE
);
udelay
(
40
);
if
(
tp
->
tg3_flags
&
TG3_FLAG_INIT_COMPLETE
)
{
udelay
(
1
);
tw32
(
MAC_MODE
,
tp
->
mac_mode
);
tr32
(
MAC_MODE
);
udelay
(
40
);
}
}
...
...
@@ -1551,7 +1664,7 @@ static void tg3_tx(struct tg3 *tp)
u32
sw_idx
=
tp
->
tx_cons
;
while
(
sw_idx
!=
hw_idx
)
{
struct
ring_info
*
ri
=
&
tp
->
tx_buffers
[
sw_idx
];
struct
tx_
ring_info
*
ri
=
&
tp
->
tx_buffers
[
sw_idx
];
struct
sk_buff
*
skb
=
ri
->
skb
;
int
i
;
...
...
@@ -1881,23 +1994,31 @@ static int tg3_rx(struct tg3 *tp, int budget)
tp
->
rx_rcb_ptr
=
rx_rcb_ptr
;
tw32_mailbox
(
MAILBOX_RCVRET_CON_IDX_0
+
TG3_64BIT_REG_LOW
,
(
rx_rcb_ptr
%
TG3_RX_RCB_RING_SIZE
));
if
(
tp
->
tg3_flags
&
TG3_FLAG_MBOX_WRITE_REORDER
)
tr32
(
MAILBOX_RCVRET_CON_IDX_0
+
TG3_64BIT_REG_LOW
);
/* Refill RX ring(s). */
if
(
work_mask
&
RXD_OPAQUE_RING_STD
)
{
sw_idx
=
tp
->
rx_std_ptr
%
TG3_RX_RING_SIZE
;
tw32_mailbox
(
MAILBOX_RCV_STD_PROD_IDX
+
TG3_64BIT_REG_LOW
,
sw_idx
);
if
(
tp
->
tg3_flags
&
TG3_FLAG_MBOX_WRITE_REORDER
)
tr32
(
MAILBOX_RCV_STD_PROD_IDX
+
TG3_64BIT_REG_LOW
);
}
if
(
work_mask
&
RXD_OPAQUE_RING_JUMBO
)
{
sw_idx
=
tp
->
rx_jumbo_ptr
%
TG3_RX_JUMBO_RING_SIZE
;
tw32_mailbox
(
MAILBOX_RCV_JUMBO_PROD_IDX
+
TG3_64BIT_REG_LOW
,
sw_idx
);
if
(
tp
->
tg3_flags
&
TG3_FLAG_MBOX_WRITE_REORDER
)
tr32
(
MAILBOX_RCV_JUMBO_PROD_IDX
+
TG3_64BIT_REG_LOW
);
}
#if TG3_MINI_RING_WORKS
if
(
work_mask
&
RXD_OPAQUE_RING_MINI
)
{
sw_idx
=
tp
->
rx_mini_ptr
%
TG3_RX_MINI_RING_SIZE
;
tw32_mailbox
(
MAILBOX_RCV_MINI_PROD_IDX
+
TG3_64BIT_REG_LOW
,
sw_idx
);
if
(
tp
->
tg3_flags
&
TG3_FLAG_MBOX_WRITE_REORDER
)
tr32
(
MAILBOX_RCV_MINI_PROD_IDX
+
TG3_64BIT_REG_LOW
);
}
#endif
...
...
@@ -1974,6 +2095,9 @@ static __inline__ void tg3_interrupt_main_work(struct net_device *dev, struct tg
return
;
if
(
netif_rx_schedule_prep
(
dev
))
{
/* NOTE: This write is posted by the readback of
* the mailbox register done by our caller.
*/
tw32
(
TG3PCI_MISC_HOST_CTRL
,
(
tp
->
misc_host_ctrl
|
MISC_HOST_CTRL_MASK_PCI_INT
));
__netif_rx_schedule
(
dev
);
...
...
@@ -1988,8 +2112,9 @@ static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
struct
net_device
*
dev
=
dev_id
;
struct
tg3
*
tp
=
dev
->
priv
;
struct
tg3_hw_status
*
sblk
=
tp
->
hw_status
;
unsigned
long
flags
;
spin_lock
(
&
tp
->
lock
);
spin_lock
_irqsave
(
&
tp
->
lock
,
flags
);
if
(
sblk
->
status
&
SD_STATUS_UPDATED
)
{
tw32_mailbox
(
MAILBOX_INTERRUPT_0
+
TG3_64BIT_REG_LOW
,
...
...
@@ -2003,7 +2128,7 @@ static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
tr32
(
MAILBOX_INTERRUPT_0
+
TG3_64BIT_REG_LOW
);
}
spin_unlock
(
&
tp
->
lock
);
spin_unlock
_irqrestore
(
&
tp
->
lock
,
flags
);
}
static
void
tg3_init_rings
(
struct
tg3
*
);
...
...
@@ -2055,11 +2180,11 @@ static void tg3_set_txd_addr(struct tg3 *tp, int entry, dma_addr_t mapping)
}
#endif
static
void
tg3_set_txd
(
struct
tg3
*
,
int
,
dma_addr_t
,
int
,
u32
,
int
);
static
void
tg3_set_txd
(
struct
tg3
*
,
int
,
dma_addr_t
,
int
,
u32
,
u32
);
static
int
tigon3_4gb_hwbug_workaround
(
struct
tg3
*
tp
,
struct
sk_buff
*
skb
,
u32
guilty_entry
,
int
guilty_len
,
u32
last_plus_one
,
u32
*
start
)
u32
last_plus_one
,
u32
*
start
,
u32
mss
)
{
dma_addr_t
new_addr
;
u32
entry
=
*
start
;
...
...
@@ -2112,7 +2237,7 @@ static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
PCI_DMA_TODEVICE
);
tg3_set_txd
(
tp
,
entry
,
new_addr
,
new_skb
->
len
,
(
skb
->
ip_summed
==
CHECKSUM_HW
)
?
TXD_FLAG_TCPUDP_CSUM
:
0
,
1
);
TXD_FLAG_TCPUDP_CSUM
:
0
,
1
|
(
mss
<<
1
)
);
*
start
=
NEXT_TX
(
entry
);
/* Now clean up the sw ring entries. */
...
...
@@ -2144,30 +2269,28 @@ static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
static
void
tg3_set_txd
(
struct
tg3
*
tp
,
int
entry
,
dma_addr_t
mapping
,
int
len
,
u32
flags
,
int
is_end
)
u32
mss_and_
is_end
)
{
#if TG3_VLAN_TAG_USED
u
16
vlan_tag
=
0
;
#endif
int
is_end
=
(
mss_and_is_end
&
0x1
);
u
32
mss
=
(
mss_and_is_end
>>
1
)
;
u32
vlan_tag
=
0
;
if
(
is_end
)
flags
|=
TXD_FLAG_END
;
#if TG3_VLAN_TAG_USED
if
(
flags
&
TXD_FLAG_VLAN
)
{
vlan_tag
=
flags
>>
16
;
flags
&=
0xffff
;
}
#endif
vlan_tag
|=
(
mss
<<
TXD_MSS_SHIFT
);
if
(
tp
->
tg3_flags
&
TG3_FLAG_HOST_TXDS
)
{
struct
tg3_tx_buffer_desc
*
txd
=
&
tp
->
tx_ring
[
entry
];
txd
->
addr_hi
=
((
u64
)
mapping
>>
32
);
txd
->
addr_lo
=
((
u64
)
mapping
&
0xffffffff
);
txd
->
len_flags
=
(
len
<<
TXD_LEN_SHIFT
)
|
flags
;
#if TG3_VLAN_TAG_USED
txd
->
vlan_tag
=
vlan_tag
<<
TXD_VLAN_TAG_SHIFT
;
#endif
}
else
{
struct
tx_ring_info
*
txr
=
&
tp
->
tx_buffers
[
entry
];
unsigned
long
txd
;
txd
=
(
tp
->
regs
+
...
...
@@ -2183,9 +2306,10 @@ static void tg3_set_txd(struct tg3 *tp, int entry,
writel
(((
u64
)
mapping
&
0xffffffff
),
txd
+
TXD_ADDR
+
TG3_64BIT_REG_LOW
);
writel
(
len
<<
TXD_LEN_SHIFT
|
flags
,
txd
+
TXD_LEN_FLAGS
);
#if TG3_VLAN_TAG_USED
writel
(
vlan_tag
<<
TXD_VLAN_TAG_SHIFT
,
txd
+
TXD_VLAN_TAG
);
#endif
if
(
txr
->
prev_vlan_tag
!=
vlan_tag
)
{
writel
(
vlan_tag
<<
TXD_VLAN_TAG_SHIFT
,
txd
+
TXD_VLAN_TAG
);
txr
->
prev_vlan_tag
=
vlan_tag
;
}
}
}
...
...
@@ -2203,7 +2327,7 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
struct
tg3
*
tp
=
dev
->
priv
;
dma_addr_t
mapping
;
unsigned
int
i
;
u32
len
,
entry
,
base_flags
;
u32
len
,
entry
,
base_flags
,
mss
;
int
would_hit_hwbug
;
len
=
(
skb
->
len
-
skb
->
data_len
);
...
...
@@ -2227,6 +2351,13 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
base_flags
=
0
;
if
(
skb
->
ip_summed
==
CHECKSUM_HW
)
base_flags
|=
TXD_FLAG_TCPUDP_CSUM
;
#if TG3_DO_TSO != 0
if
((
mss
=
skb_shinfo
(
skb
)
->
tso_size
)
!=
0
)
base_flags
|=
(
TXD_FLAG_CPU_PRE_DMA
|
TXD_FLAG_CPU_POST_DMA
);
#else
mss
=
0
;
#endif
#if TG3_VLAN_TAG_USED
if
(
tp
->
vlgrp
!=
NULL
&&
vlan_tx_tag_present
(
skb
))
base_flags
|=
(
TXD_FLAG_VLAN
|
...
...
@@ -2245,7 +2376,7 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
would_hit_hwbug
=
entry
+
1
;
tg3_set_txd
(
tp
,
entry
,
mapping
,
len
,
base_flags
,
(
skb_shinfo
(
skb
)
->
nr_frags
==
0
));
(
skb_shinfo
(
skb
)
->
nr_frags
==
0
)
|
(
mss
<<
1
)
);
entry
=
NEXT_TX
(
entry
);
...
...
@@ -2274,7 +2405,7 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
}
tg3_set_txd
(
tp
,
entry
,
mapping
,
len
,
base_flags
,
(
i
==
last
));
base_flags
,
(
i
==
last
)
|
(
mss
<<
1
)
);
entry
=
NEXT_TX
(
entry
);
}
...
...
@@ -2310,7 +2441,7 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
if
(
tigon3_4gb_hwbug_workaround
(
tp
,
skb
,
entry
,
len
,
last_plus_one
,
&
start
))
&
start
,
mss
))
goto
out_unlock
;
entry
=
start
;
...
...
@@ -2323,12 +2454,27 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev)
if
(
tp
->
tg3_flags
&
TG3_FLAG_TXD_MBOX_HWBUG
)
tw32_mailbox
((
MAILBOX_SNDHOST_PROD_IDX_0
+
TG3_64BIT_REG_LOW
),
entry
);
if
(
tp
->
tg3_flags
&
TG3_FLAG_MBOX_WRITE_REORDER
)
tr32
(
MAILBOX_SNDHOST_PROD_IDX_0
+
TG3_64BIT_REG_LOW
);
}
else
{
/* First, make sure tg3 sees last descriptor fully
* in SRAM.
*/
if
(
tp
->
tg3_flags
&
TG3_FLAG_MBOX_WRITE_REORDER
)
tr32
(
MAILBOX_SNDNIC_PROD_IDX_0
+
TG3_64BIT_REG_LOW
);
tw32_mailbox
((
MAILBOX_SNDNIC_PROD_IDX_0
+
TG3_64BIT_REG_LOW
),
entry
);
if
(
tp
->
tg3_flags
&
TG3_FLAG_TXD_MBOX_HWBUG
)
tw32_mailbox
((
MAILBOX_SNDNIC_PROD_IDX_0
+
TG3_64BIT_REG_LOW
),
entry
);
/* Now post the mailbox write itself. */
if
(
tp
->
tg3_flags
&
TG3_FLAG_MBOX_WRITE_REORDER
)
tr32
(
MAILBOX_SNDNIC_PROD_IDX_0
+
TG3_64BIT_REG_LOW
);
}
tp
->
tx_prod
=
entry
;
...
...
@@ -2347,7 +2493,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct
tg3
*
tp
=
dev
->
priv
;
dma_addr_t
mapping
;
u32
len
,
entry
,
base_flags
;
u32
len
,
entry
,
base_flags
,
mss
;
len
=
(
skb
->
len
-
skb
->
data_len
);
...
...
@@ -2370,6 +2516,13 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
base_flags
=
0
;
if
(
skb
->
ip_summed
==
CHECKSUM_HW
)
base_flags
|=
TXD_FLAG_TCPUDP_CSUM
;
#if TG3_DO_TSO != 0
if
((
mss
=
skb_shinfo
(
skb
)
->
tso_size
)
!=
0
)
base_flags
|=
(
TXD_FLAG_CPU_PRE_DMA
|
TXD_FLAG_CPU_POST_DMA
);
#else
mss
=
0
;
#endif
#if TG3_VLAN_TAG_USED
if
(
tp
->
vlgrp
!=
NULL
&&
vlan_tx_tag_present
(
skb
))
base_flags
|=
(
TXD_FLAG_VLAN
|
...
...
@@ -2383,7 +2536,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
pci_unmap_addr_set
(
&
tp
->
tx_buffers
[
entry
],
mapping
,
mapping
);
tg3_set_txd
(
tp
,
entry
,
mapping
,
len
,
base_flags
,
(
skb_shinfo
(
skb
)
->
nr_frags
==
0
));
(
skb_shinfo
(
skb
)
->
nr_frags
==
0
)
|
(
mss
<<
1
)
);
entry
=
NEXT_TX
(
entry
);
...
...
@@ -2406,7 +2559,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
pci_unmap_addr_set
(
&
tp
->
tx_buffers
[
entry
],
mapping
,
mapping
);
tg3_set_txd
(
tp
,
entry
,
mapping
,
len
,
base_flags
,
(
i
==
last
));
base_flags
,
(
i
==
last
)
|
(
mss
<<
1
)
);
entry
=
NEXT_TX
(
entry
);
}
...
...
@@ -2420,9 +2573,24 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev)
if
(
tp
->
tg3_flags
&
TG3_FLAG_HOST_TXDS
)
{
tw32_mailbox
((
MAILBOX_SNDHOST_PROD_IDX_0
+
TG3_64BIT_REG_LOW
),
entry
);
if
(
tp
->
tg3_flags
&
TG3_FLAG_MBOX_WRITE_REORDER
)
tr32
(
MAILBOX_SNDHOST_PROD_IDX_0
+
TG3_64BIT_REG_LOW
);
}
else
{
/* First, make sure tg3 sees last descriptor fully
* in SRAM.
*/
if
(
tp
->
tg3_flags
&
TG3_FLAG_MBOX_WRITE_REORDER
)
tr32
(
MAILBOX_SNDNIC_PROD_IDX_0
+
TG3_64BIT_REG_LOW
);
tw32_mailbox
((
MAILBOX_SNDNIC_PROD_IDX_0
+
TG3_64BIT_REG_LOW
),
entry
);
/* Now post the mailbox write itself. */
if
(
tp
->
tg3_flags
&
TG3_FLAG_MBOX_WRITE_REORDER
)
tr32
(
MAILBOX_SNDNIC_PROD_IDX_0
+
TG3_64BIT_REG_LOW
);
}
tp
->
tx_prod
=
entry
;
...
...
@@ -2524,7 +2692,7 @@ static void tg3_free_rings(struct tg3 *tp)
}
for
(
i
=
0
;
i
<
TG3_TX_RING_SIZE
;
)
{
struct
ring_info
*
txp
;
struct
tx_
ring_info
*
txp
;
struct
sk_buff
*
skb
;
int
j
;
...
...
@@ -2591,6 +2759,8 @@ static void tg3_init_rings(struct tg3 *tp)
writel
(
0
,
start
);
start
+=
4
;
}
for
(
i
=
0
;
i
<
TG3_TX_RING_SIZE
;
i
++
)
tp
->
tx_buffers
[
i
].
prev_vlan_tag
=
0
;
}
/* Initialize invariants of the rings, we only set this
...
...
@@ -2713,12 +2883,13 @@ static void tg3_free_consistent(struct tg3 *tp)
*/
static
int
tg3_alloc_consistent
(
struct
tg3
*
tp
)
{
tp
->
rx_std_buffers
=
kmalloc
(
sizeof
(
struct
ring_info
)
*
(
TG3_RX_RING_SIZE
+
tp
->
rx_std_buffers
=
kmalloc
(
(
sizeof
(
struct
ring_info
)
*
(
TG3_RX_RING_SIZE
+
#if TG3_MINI_RING_WORKS
TG3_RX_MINI_RING_SIZE
+
TG3_RX_MINI_RING_SIZE
+
#endif
TG3_RX_JUMBO_RING_SIZE
+
TG3_RX_JUMBO_RING_SIZE
))
+
(
sizeof
(
struct
tx_ring_info
)
*
TG3_TX_RING_SIZE
),
GFP_KERNEL
);
if
(
!
tp
->
rx_std_buffers
)
...
...
@@ -2729,14 +2900,16 @@ static int tg3_alloc_consistent(struct tg3 *tp)
(
sizeof
(
struct
ring_info
)
*
(
TG3_RX_RING_SIZE
+
TG3_RX_MINI_RING_SIZE
+
TG3_RX_JUMBO_RING_SIZE
+
TG3_TX_RING_SIZE
)));
TG3_RX_JUMBO_RING_SIZE
))
+
(
sizeof
(
struct
tx_ring_info
)
*
TG3_TX_RING_SIZE
));
#else
memset
(
tp
->
rx_std_buffers
,
0
,
(
sizeof
(
struct
ring_info
)
*
(
TG3_RX_RING_SIZE
+
TG3_RX_JUMBO_RING_SIZE
+
TG3_TX_RING_SIZE
)));
TG3_RX_JUMBO_RING_SIZE
))
+
(
sizeof
(
struct
tx_ring_info
)
*
TG3_TX_RING_SIZE
));
#endif
#if TG3_MINI_RING_WORKS
...
...
@@ -2745,7 +2918,8 @@ static int tg3_alloc_consistent(struct tg3 *tp)
#else
tp
->
rx_jumbo_buffers
=
&
tp
->
rx_std_buffers
[
TG3_RX_RING_SIZE
];
#endif
tp
->
tx_buffers
=
&
tp
->
rx_jumbo_buffers
[
TG3_RX_JUMBO_RING_SIZE
];
tp
->
tx_buffers
=
(
struct
tx_ring_info
*
)
&
tp
->
rx_jumbo_buffers
[
TG3_RX_JUMBO_RING_SIZE
];
tp
->
rx_std
=
pci_alloc_consistent
(
tp
->
pdev
,
TG3_RX_RING_BYTES
,
&
tp
->
rx_std_mapping
);
...
...
@@ -2816,13 +2990,13 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit)
val
=
tr32
(
ofs
);
val
&=
~
enable_bit
;
tw32
(
ofs
,
val
);
tr32
(
ofs
);
for
(
i
=
0
;
i
<
MAX_WAIT_CNT
;
i
++
)
{
udelay
(
100
);
val
=
tr32
(
ofs
);
if
((
val
&
enable_bit
)
==
0
)
break
;
udelay
(
100
);
}
if
(
i
==
MAX_WAIT_CNT
)
{
...
...
@@ -2844,6 +3018,8 @@ static int tg3_abort_hw(struct tg3 *tp)
tp
->
rx_mode
&=
~
RX_MODE_ENABLE
;
tw32
(
MAC_RX_MODE
,
tp
->
rx_mode
);
tr32
(
MAC_RX_MODE
);
udelay
(
10
);
err
=
tg3_stop_block
(
tp
,
RCVBDI_MODE
,
RCVBDI_MODE_ENABLE
);
err
|=
tg3_stop_block
(
tp
,
RCVLPC_MODE
,
RCVLPC_MODE_ENABLE
);
...
...
@@ -2863,9 +3039,13 @@ static int tg3_abort_hw(struct tg3 *tp)
tp
->
mac_mode
&=
~
MAC_MODE_TDE_ENABLE
;
tw32
(
MAC_MODE
,
tp
->
mac_mode
);
tr32
(
MAC_MODE
);
udelay
(
40
);
tp
->
tx_mode
&=
~
TX_MODE_ENABLE
;
tw32
(
MAC_TX_MODE
,
tp
->
tx_mode
);
tr32
(
MAC_TX_MODE
);
for
(
i
=
0
;
i
<
MAX_WAIT_CNT
;
i
++
)
{
udelay
(
100
);
if
(
!
(
tr32
(
MAC_TX_MODE
)
&
TX_MODE_ENABLE
))
...
...
@@ -2917,6 +3097,14 @@ static void tg3_chip_reset(struct tg3 *tp)
}
tw32
(
GRC_MISC_CFG
,
GRC_MISC_CFG_CORECLK_RESET
);
/* Flush PCI posted writes. The normal MMIO registers
* are inaccessible at this time so this is the only
* way to make this reliably. I tried to use indirect
* register read/write but this upset some 5701 variants.
*/
pci_read_config_dword
(
tp
->
pdev
,
PCI_COMMAND
,
&
val
);
udelay
(
40
);
udelay
(
40
);
udelay
(
40
);
...
...
@@ -2926,9 +3114,11 @@ static void tg3_chip_reset(struct tg3 *tp)
tp
->
misc_host_ctrl
);
/* Set MAX PCI retry to zero. */
pci_write_config_dword
(
tp
->
pdev
,
TG3PCI_PCISTATE
,
(
PCISTATE_ROM_ENABLE
|
PCISTATE_ROM_RETRY_ENABLE
));
val
=
(
PCISTATE_ROM_ENABLE
|
PCISTATE_ROM_RETRY_ENABLE
);
if
(
tp
->
pci_chip_rev_id
==
CHIPREV_ID_5704_A0
&&
(
tp
->
tg3_flags
&
TG3_FLAG_PCIX_MODE
))
val
|=
PCISTATE_RETRY_SAME_DMA
;
pci_write_config_dword
(
tp
->
pdev
,
TG3PCI_PCISTATE
,
val
);
pci_restore_state
(
tp
->
pdev
,
tp
->
pci_cfg_state
);
...
...
@@ -2942,12 +3132,34 @@ static void tg3_chip_reset(struct tg3 *tp)
tw32
(
TG3PCI_MISC_HOST_CTRL
,
tp
->
misc_host_ctrl
);
}
/* tp->lock is held. */
static
void
tg3_stop_fw
(
struct
tg3
*
tp
)
{
if
(
tp
->
tg3_flags
&
TG3_FLAG_ENABLE_ASF
)
{
u32
val
;
int
i
;
tg3_write_mem
(
tp
,
NIC_SRAM_FW_CMD_MBOX
,
FWCMD_NICDRV_PAUSE_FW
);
val
=
tr32
(
GRC_RX_CPU_EVENT
);
val
|=
(
1
<<
14
);
tw32
(
GRC_RX_CPU_EVENT
,
val
);
/* Wait for RX cpu to ACK the event. */
for
(
i
=
0
;
i
<
100
;
i
++
)
{
if
(
!
(
tr32
(
GRC_RX_CPU_EVENT
)
&
(
1
<<
14
)))
break
;
udelay
(
1
);
}
}
}
/* tp->lock is held. */
static
int
tg3_halt
(
struct
tg3
*
tp
)
{
u32
val
;
int
i
;
tg3_stop_fw
(
tp
);
tg3_abort_hw
(
tp
);
tg3_chip_reset
(
tp
);
tg3_write_mem
(
tp
,
...
...
@@ -2967,6 +3179,17 @@ static int tg3_halt(struct tg3 *tp)
return
-
ENODEV
;
}
if
(
tp
->
tg3_flags
&
TG3_FLAG_ENABLE_ASF
)
{
if
(
tp
->
tg3_flags
&
TG3_FLAG_WOL_ENABLE
)
tg3_write_mem
(
tp
,
NIC_SRAM_FW_DRV_STATE_MBOX
,
DRV_STATE_WOL
);
else
tg3_write_mem
(
tp
,
NIC_SRAM_FW_DRV_STATE_MBOX
,
DRV_STATE_UNLOAD
);
}
else
tg3_write_mem
(
tp
,
NIC_SRAM_FW_DRV_STATE_MBOX
,
DRV_STATE_SUSPEND
);
return
0
;
}
...
...
@@ -2985,7 +3208,7 @@ static int tg3_halt(struct tg3 *tp)
#define TG3_FW_BSS_ADDR 0x08000a70
#define TG3_FW_BSS_LEN 0x10
static
u32
t3FwText
[(
TG3_FW_TEXT_LEN
/
sizeof
(
u32
))
+
1
]
=
{
static
u32
t
g
3FwText
[(
TG3_FW_TEXT_LEN
/
sizeof
(
u32
))
+
1
]
=
{
0x00000000
,
0x10000003
,
0x00000000
,
0x0000000d
,
0x0000000d
,
0x3c1d0800
,
0x37bd3ffc
,
0x03a0f021
,
0x3c100800
,
0x26100000
,
0x0e000018
,
0x00000000
,
0x0000000d
,
0x3c1d0800
,
0x37bd3ffc
,
0x03a0f021
,
0x3c100800
,
0x26100034
,
...
...
@@ -3079,7 +3302,7 @@ static u32 t3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = {
0x27bd0008
,
0x03e00008
,
0x00000000
,
0x00000000
,
0x00000000
};
static
u32
t3FwRodata
[(
TG3_FW_RODATA_LEN
/
sizeof
(
u32
))
+
1
]
=
{
static
u32
t
g
3FwRodata
[(
TG3_FW_RODATA_LEN
/
sizeof
(
u32
))
+
1
]
=
{
0x35373031
,
0x726c7341
,
0x00000000
,
0x00000000
,
0x53774576
,
0x656e7430
,
0x00000000
,
0x726c7045
,
0x76656e74
,
0x31000000
,
0x556e6b6e
,
0x45766e74
,
0x00000000
,
0x00000000
,
0x00000000
,
0x00000000
,
0x66617461
,
0x6c457272
,
...
...
@@ -3088,7 +3311,7 @@ static u32 t3FwRodata[(TG3_FW_RODATA_LEN / sizeof(u32)) + 1] = {
};
#if 0 /* All zeros, dont eat up space with it. */
u32 t3FwData[(TG3_FW_DATA_LEN / sizeof(u32)) + 1] = {
u32 t
g
3FwData[(TG3_FW_DATA_LEN / sizeof(u32)) + 1] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000
};
...
...
@@ -3112,6 +3335,7 @@ static int tg3_reset_cpu(struct tg3 *tp, u32 offset)
break
;
tw32
(
offset
+
CPU_STATE
,
0xffffffff
);
tw32
(
offset
+
CPU_MODE
,
CPU_MODE_RESET
);
tr32
(
offset
+
CPU_MODE
);
udelay
(
10
);
}
else
{
for
(
i
=
0
;
i
<
10000
;
i
++
)
{
...
...
@@ -3119,6 +3343,7 @@ static int tg3_reset_cpu(struct tg3 *tp, u32 offset)
break
;
tw32
(
offset
+
CPU_STATE
,
0xffffffff
);
tw32
(
offset
+
CPU_MODE
,
CPU_MODE_RESET
);
tr32
(
offset
+
CPU_MODE
);
udelay
(
10
);
}
}
...
...
@@ -3133,51 +3358,89 @@ static int tg3_reset_cpu(struct tg3 *tp, u32 offset)
return
0
;
}
struct
fw_info
{
unsigned
int
text_base
;
unsigned
int
text_len
;
u32
*
text_data
;
unsigned
int
rodata_base
;
unsigned
int
rodata_len
;
u32
*
rodata_data
;
unsigned
int
data_base
;
unsigned
int
data_len
;
u32
*
data_data
;
};
/* tp->lock is held. */
static
int
tg3_load_firmware_cpu
(
struct
tg3
*
tp
,
u32
cpu_base
,
u32
cpu_scratch_base
,
int
cpu_scratch_size
)
int
cpu_scratch_size
,
struct
fw_info
*
info
)
{
int
err
,
i
;
u32
orig_tg3_flags
=
tp
->
tg3_flags
;
/* Force use of PCI config space for indirect register
* write calls.
*/
tp
->
tg3_flags
|=
TG3_FLAG_PCIX_TARGET_HWBUG
;
err
=
tg3_reset_cpu
(
tp
,
cpu_base
);
if
(
err
)
return
err
;
goto
out
;
for
(
i
=
0
;
i
<
cpu_scratch_size
;
i
+=
sizeof
(
u32
))
tg3_write_indirect_reg32
(
tp
,
cpu_scratch_base
+
i
,
0
);
tw32
(
cpu_base
+
CPU_STATE
,
0xffffffff
);
tw32
(
cpu_base
+
CPU_MODE
,
tr32
(
cpu_base
+
CPU_MODE
)
|
CPU_MODE_HALT
);
for
(
i
=
0
;
i
<
(
TG3_FW_TEXT_LEN
/
sizeof
(
u32
));
i
++
)
for
(
i
=
0
;
i
<
(
info
->
text_len
/
sizeof
(
u32
));
i
++
)
tg3_write_indirect_reg32
(
tp
,
(
cpu_scratch_base
+
(
TG3_FW_TEXT_ADDR
&
0xffff
)
+
(
info
->
text_base
&
0xffff
)
+
(
i
*
sizeof
(
u32
))),
t3FwText
[
i
]);
for
(
i
=
0
;
i
<
(
TG3_FW_RODATA_LEN
/
sizeof
(
u32
));
i
++
)
(
info
->
text_data
?
info
->
text_data
[
i
]
:
0
));
for
(
i
=
0
;
i
<
(
info
->
rodata_len
/
sizeof
(
u32
));
i
++
)
tg3_write_indirect_reg32
(
tp
,
(
cpu_scratch_base
+
(
TG3_FW_RODATA_ADDR
&
0xffff
)
+
(
info
->
rodata_base
&
0xffff
)
+
(
i
*
sizeof
(
u32
))),
t3FwRodata
[
i
]);
for
(
i
=
0
;
i
<
(
TG3_FW_DATA_LEN
/
sizeof
(
u32
));
i
++
)
(
info
->
rodata_data
?
info
->
rodata_data
[
i
]
:
0
));
for
(
i
=
0
;
i
<
(
info
->
data_len
/
sizeof
(
u32
));
i
++
)
tg3_write_indirect_reg32
(
tp
,
(
cpu_scratch_base
+
(
TG3_FW_DATA_ADDR
&
0xffff
)
+
(
info
->
data_base
&
0xffff
)
+
(
i
*
sizeof
(
u32
))),
0
);
(
info
->
data_data
?
info
->
data_data
[
i
]
:
0
));
return
0
;
err
=
0
;
out:
tp
->
tg3_flags
=
orig_tg3_flags
;
return
err
;
}
/* tp->lock is held. */
static
int
tg3_load_5701_a0_firmware_fix
(
struct
tg3
*
tp
)
{
struct
fw_info
info
;
int
err
,
i
;
info
.
text_base
=
TG3_FW_TEXT_ADDR
;
info
.
text_len
=
TG3_FW_TEXT_LEN
;
info
.
text_data
=
&
tg3FwText
[
0
];
info
.
rodata_base
=
TG3_FW_RODATA_ADDR
;
info
.
rodata_len
=
TG3_FW_RODATA_LEN
;
info
.
rodata_data
=
&
tg3FwRodata
[
0
];
info
.
data_base
=
TG3_FW_DATA_ADDR
;
info
.
data_len
=
TG3_FW_DATA_LEN
;
info
.
data_data
=
NULL
;
err
=
tg3_load_firmware_cpu
(
tp
,
RX_CPU_BASE
,
RX_CPU_SCRATCH_BASE
,
RX_CPU_SCRATCH_SIZE
);
RX_CPU_SCRATCH_BASE
,
RX_CPU_SCRATCH_SIZE
,
&
info
);
if
(
err
)
return
err
;
err
=
tg3_load_firmware_cpu
(
tp
,
TX_CPU_BASE
,
TX_CPU_SCRATCH_BASE
,
TX_CPU_SCRATCH_SIZE
);
TX_CPU_SCRATCH_BASE
,
TX_CPU_SCRATCH_SIZE
,
&
info
);
if
(
err
)
return
err
;
...
...
@@ -3215,6 +3478,336 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp)
return
0
;
}
#if TG3_DO_TSO != 0
#define TG3_TSO_FW_RELEASE_MAJOR 0x1
#define TG3_TSO_FW_RELASE_MINOR 0x8
#define TG3_TSO_FW_RELEASE_FIX 0x0
#define TG3_TSO_FW_START_ADDR 0x08000000
#define TG3_TSO_FW_TEXT_ADDR 0x08000000
#define TG3_TSO_FW_TEXT_LEN 0x1650
#define TG3_TSO_FW_RODATA_ADDR 0x08001650
#define TG3_TSO_FW_RODATA_LEN 0x30
#define TG3_TSO_FW_DATA_ADDR 0x080016a0
#define TG3_TSO_FW_DATA_LEN 0x20
#define TG3_TSO_FW_SBSS_ADDR 0x080016c0
#define TG3_TSO_FW_SBSS_LEN 0x14
#define TG3_TSO_FW_BSS_ADDR 0x080016e0
#define TG3_TSO_FW_BSS_LEN 0x8fc
static
u32
tg3TsoFwText
[]
=
{
0x00000000
,
0x10000003
,
0x00000000
,
0x0000000d
,
0x0000000d
,
0x3c1d0800
,
0x37bd4000
,
0x03a0f021
,
0x3c100800
,
0x26100000
,
0x0e000010
,
0x00000000
,
0x0000000d
,
0x00000000
,
0x00000000
,
0x00000000
,
0x27bdffe0
,
0x3c1bc000
,
0xafbf0018
,
0x0e000058
,
0xaf60680c
,
0x3c040800
,
0x24841650
,
0x03602821
,
0x24060001
,
0x24070004
,
0xafa00010
,
0x0e00006c
,
0xafa00014
,
0x8f625c50
,
0x34420001
,
0xaf625c50
,
0x8f625c90
,
0x34420001
,
0xaf625c90
,
0x2402ffff
,
0x0e000098
,
0xaf625404
,
0x8fbf0018
,
0x03e00008
,
0x27bd0020
,
0x00000000
,
0x00000000
,
0x00000000
,
0x24030b60
,
0x24050fff
,
0xac000b50
,
0x00002021
,
0xac640000
,
0x24630004
,
0x0065102b
,
0x1440fffc
,
0x24840001
,
0x24030b60
,
0x0065102b
,
0x10400011
,
0x00002021
,
0x24090b54
,
0x3c06dead
,
0x34c6beef
,
0x24080b58
,
0x24070b5c
,
0x8c620000
,
0x50440006
,
0x24630004
,
0xad260000
,
0x8c620000
,
0xace40000
,
0xad020000
,
0x24630004
,
0x0065102b
,
0x1440fff6
,
0x24840001
,
0x03e00008
,
0x00000000
,
0x27bdfff8
,
0x18800009
,
0x00002821
,
0x8f63680c
,
0x8f62680c
,
0x1043fffe
,
0x00000000
,
0x24a50001
,
0x00a4102a
,
0x1440fff9
,
0x00000000
,
0x03e00008
,
0x27bd0008
,
0x3c020800
,
0x34423000
,
0x3c030800
,
0x34633000
,
0x3c040800
,
0x348437ff
,
0x3c010800
,
0xac2216c4
,
0x24020040
,
0x3c010800
,
0xac2216c8
,
0x3c010800
,
0xac2016c0
,
0xac600000
,
0x24630004
,
0x0083102b
,
0x5040fffd
,
0xac600000
,
0x03e00008
,
0x00000000
,
0x00804821
,
0x8faa0010
,
0x3c020800
,
0x8c4216c0
,
0x3c040800
,
0x8c8416c8
,
0x8fab0014
,
0x24430001
,
0x0044102b
,
0x3c010800
,
0xac2316c0
,
0x14400003
,
0x00004021
,
0x3c010800
,
0xac2016c0
,
0x3c020800
,
0x8c4216c0
,
0x3c030800
,
0x8c6316c4
,
0x91240000
,
0x00021140
,
0x00431021
,
0x00481021
,
0x25080001
,
0xa0440000
,
0x29020008
,
0x1440fff4
,
0x25290001
,
0x3c020800
,
0x8c4216c0
,
0x3c030800
,
0x8c6316c4
,
0x8f64680c
,
0x00021140
,
0x00431021
,
0xac440008
,
0xac45000c
,
0xac460010
,
0xac470014
,
0xac4a0018
,
0x03e00008
,
0xac4b001c
,
0x00000000
,
0x00000000
,
0x27bdffe0
,
0xafbf0018
,
0xafb10014
,
0x0e0000b6
,
0xafb00010
,
0x24110001
,
0x8f706820
,
0x32020100
,
0x10400003
,
0x00000000
,
0x0e000127
,
0x00000000
,
0x8f706820
,
0x32022000
,
0x10400004
,
0x32020001
,
0x0e00025a
,
0x24040001
,
0x32020001
,
0x10400003
,
0x00000000
,
0x0e0000e6
,
0x00000000
,
0x0a00009e
,
0xaf715028
,
0x8fbf0018
,
0x8fb10014
,
0x8fb00010
,
0x03e00008
,
0x27bd0020
,
0x27bdffe0
,
0x3c040800
,
0x24841660
,
0x00002821
,
0x00003021
,
0x00003821
,
0xafbf0018
,
0xafa00010
,
0x0e00006c
,
0xafa00014
,
0x3c010800
,
0xa4201fb8
,
0x3c010800
,
0xa02016f8
,
0x3c010800
,
0xac2016fc
,
0x3c010800
,
0xac201700
,
0x3c010800
,
0xac201704
,
0x3c010800
,
0xac20170c
,
0x3c010800
,
0xac201718
,
0x3c010800
,
0xac20171c
,
0x8f624434
,
0x3c010800
,
0xac2216e8
,
0x8f624438
,
0x3c010800
,
0xac2216ec
,
0x8f624410
,
0x3c010800
,
0xac2016e0
,
0x3c010800
,
0xac2016e4
,
0x3c010800
,
0xac201fc0
,
0x3c010800
,
0xac201f68
,
0x3c010800
,
0xac201f6c
,
0x3c010800
,
0xac2216f0
,
0x8fbf0018
,
0x03e00008
,
0x27bd0020
,
0x27bdffe0
,
0x3c040800
,
0x2484166c
,
0x00002821
,
0x00003021
,
0x00003821
,
0xafbf0018
,
0xafa00010
,
0x0e00006c
,
0xafa00014
,
0x3c040800
,
0x24841660
,
0x00002821
,
0x00003021
,
0x00003821
,
0xafa00010
,
0x0e00006c
,
0xafa00014
,
0x3c010800
,
0xa4201fb8
,
0x3c010800
,
0xa02016f8
,
0x3c010800
,
0xac2016fc
,
0x3c010800
,
0xac201700
,
0x3c010800
,
0xac201704
,
0x3c010800
,
0xac20170c
,
0x3c010800
,
0xac201718
,
0x3c010800
,
0xac20171c
,
0x8f624434
,
0x3c010800
,
0xac2216e8
,
0x8f624438
,
0x3c010800
,
0xac2216ec
,
0x8f624410
,
0x3c010800
,
0xac2016e0
,
0x3c010800
,
0xac2016e4
,
0x3c010800
,
0xac201fc0
,
0x3c010800
,
0xac201f68
,
0x3c010800
,
0xac201f6c
,
0x3c010800
,
0xac2216f0
,
0x0e000120
,
0x00002021
,
0x8fbf0018
,
0x03e00008
,
0x27bd0020
,
0x24020001
,
0x8f636820
,
0x00821004
,
0x00021027
,
0x00621824
,
0x03e00008
,
0xaf636820
,
0x27bdffd0
,
0x3c0300ff
,
0xafbf002c
,
0xafb60028
,
0xafb50024
,
0xafb40020
,
0xafb3001c
,
0xafb20018
,
0xafb10014
,
0xafb00010
,
0x8f665c5c
,
0x3c040800
,
0x2484171c
,
0x8c820000
,
0x3463fff8
,
0x14460005
,
0x00c38824
,
0x3c020800
,
0x904216f8
,
0x14400115
,
0x00000000
,
0x00111902
,
0x306300ff
,
0x30c20003
,
0x000211c0
,
0x00623825
,
0x00e02821
,
0x00061602
,
0xac860000
,
0x3c030800
,
0x906316f8
,
0x3044000f
,
0x1460002b
,
0x00804021
,
0x24020001
,
0x3c010800
,
0xa02216f8
,
0x00071100
,
0x00821025
,
0x3c010800
,
0xac2016fc
,
0x3c010800
,
0xac201700
,
0x3c010800
,
0xac201704
,
0x3c010800
,
0xac20170c
,
0x3c010800
,
0xac201718
,
0x3c010800
,
0xac201710
,
0x3c010800
,
0xac201714
,
0x3c010800
,
0xa4221fb8
,
0x9623000c
,
0x30628000
,
0x10400008
,
0x30627fff
,
0x2442003e
,
0x3c010800
,
0xa42216f6
,
0x24020001
,
0x3c010800
,
0x0a00016e
,
0xac221fd4
,
0x24620036
,
0x3c010800
,
0xa42216f6
,
0x3c010800
,
0xac201fd4
,
0x3c010800
,
0xac201fd0
,
0x3c010800
,
0x0a000176
,
0xac201fd8
,
0x9622000c
,
0x3c010800
,
0xa4221fcc
,
0x3c040800
,
0x248416fc
,
0x8c820000
,
0x00021100
,
0x3c010800
,
0x00220821
,
0xac311728
,
0x8c820000
,
0x00021100
,
0x3c010800
,
0x00220821
,
0xac26172c
,
0x8c820000
,
0x24a30001
,
0x306701ff
,
0x00021100
,
0x3c010800
,
0x00220821
,
0xac271730
,
0x8c820000
,
0x00021100
,
0x3c010800
,
0x00220821
,
0xac281734
,
0x96230008
,
0x3c020800
,
0x8c42170c
,
0x00432821
,
0x3c010800
,
0xac25170c
,
0x9622000a
,
0x30420004
,
0x14400019
,
0x00071100
,
0x3c02c000
,
0x00c21825
,
0xaf635c5c
,
0x8f625c50
,
0x30420002
,
0x1440fffc
,
0x00000000
,
0x8f630c14
,
0x3063000f
,
0x2c620002
,
0x1440001e
,
0x00000000
,
0x8f630c14
,
0x3c020800
,
0x8c4216b4
,
0x3063000f
,
0x24420001
,
0x3c010800
,
0xac2216b4
,
0x2c620002
,
0x1040fff7
,
0x00000000
,
0x0a0001c1
,
0x00000000
,
0x3c030800
,
0x8c6316e0
,
0x3c040800
,
0x948416f4
,
0x01021025
,
0x3c010800
,
0xa4221fba
,
0x24020001
,
0x3c010800
,
0xac221718
,
0x24630001
,
0x0085202a
,
0x3c010800
,
0x10800003
,
0xac2316e0
,
0x3c010800
,
0xa42516f4
,
0x3c030800
,
0x246316fc
,
0x8c620000
,
0x24420001
,
0xac620000
,
0x28420080
,
0x14400005
,
0x24020001
,
0x0e0002df
,
0x24040002
,
0x0a000250
,
0x00000000
,
0x3c030800
,
0x906316f8
,
0x1462007c
,
0x24020003
,
0x3c160800
,
0x96d616f6
,
0x3c050800
,
0x8ca5170c
,
0x32c4ffff
,
0x00a4102a
,
0x14400078
,
0x00000000
,
0x3c020800
,
0x8c421718
,
0x10400005
,
0x32c2ffff
,
0x14a40003
,
0x00000000
,
0x3c010800
,
0xac231fd0
,
0x10400062
,
0x00009021
,
0x0040a021
,
0x3c150800
,
0x26b51700
,
0x26b30010
,
0x8ea20000
,
0x00028100
,
0x3c110800
,
0x02308821
,
0x0e0002e1
,
0x8e311728
,
0x00403021
,
0x10c00059
,
0x00000000
,
0x9628000a
,
0x31020040
,
0x10400004
,
0x2407180c
,
0x8e22000c
,
0x2407188c
,
0xacc20018
,
0x31021000
,
0x10400004
,
0x34e32000
,
0x00081040
,
0x3042c000
,
0x00623825
,
0x3c030800
,
0x00701821
,
0x8c631730
,
0x3c020800
,
0x00501021
,
0x8c421734
,
0x00031d00
,
0x00021400
,
0x00621825
,
0xacc30014
,
0x8ea30004
,
0x96220008
,
0x00432023
,
0x3242ffff
,
0x3083ffff
,
0x00431021
,
0x0282102a
,
0x14400002
,
0x02d22823
,
0x00802821
,
0x8e620000
,
0x30a4ffff
,
0x00441021
,
0xae620000
,
0x8e220000
,
0xacc20000
,
0x8e220004
,
0x8e63fff4
,
0x00431021
,
0xacc20004
,
0xa4c5000e
,
0x8e62fff4
,
0x00441021
,
0xae62fff4
,
0x96230008
,
0x0043102a
,
0x14400005
,
0x02459021
,
0x8e62fff0
,
0xae60fff4
,
0x24420001
,
0xae62fff0
,
0xacc00008
,
0x3242ffff
,
0x14540008
,
0x24020305
,
0x31020080
,
0x54400001
,
0x34e70010
,
0x24020905
,
0xa4c2000c
,
0x0a000233
,
0x34e70020
,
0xa4c2000c
,
0x30e2ffff
,
0xacc20010
,
0x3c020800
,
0x8c421fd0
,
0x10400003
,
0x3c024b65
,
0x0a00023d
,
0x34427654
,
0x3c02b49a
,
0x344289ab
,
0xacc2001c
,
0x0e000560
,
0x00c02021
,
0x3242ffff
,
0x0054102b
,
0x1440ffa4
,
0x00000000
,
0x24020002
,
0x3c010800
,
0x0a000250
,
0xa02216f8
,
0x8ea208bc
,
0x24420001
,
0x0a000250
,
0xaea208bc
,
0x14620003
,
0x00000000
,
0x0e000450
,
0x00000000
,
0x8fbf002c
,
0x8fb60028
,
0x8fb50024
,
0x8fb40020
,
0x8fb3001c
,
0x8fb20018
,
0x8fb10014
,
0x8fb00010
,
0x03e00008
,
0x27bd0030
,
0x27bdffd8
,
0xafb3001c
,
0x00809821
,
0xafbf0020
,
0xafb20018
,
0xafb10014
,
0xafb00010
,
0x8f725c9c
,
0x3c0200ff
,
0x3442fff8
,
0x3c040800
,
0x24841714
,
0x02428824
,
0x9623000e
,
0x8c820000
,
0x00431021
,
0xac820000
,
0x8e220010
,
0x30420020
,
0x14400011
,
0x00000000
,
0x0e0002f7
,
0x02202021
,
0x3c02c000
,
0x02421825
,
0xaf635c9c
,
0x8f625c90
,
0x30420002
,
0x10400061
,
0x00000000
,
0xaf635c9c
,
0x8f625c90
,
0x30420002
,
0x1040005c
,
0x00000000
,
0x0a000278
,
0x00000000
,
0x8e220008
,
0x00021c02
,
0x000321c0
,
0x3042ffff
,
0x3c030800
,
0x906316f8
,
0x000229c0
,
0x24020002
,
0x14620003
,
0x3c034b65
,
0x0a000290
,
0x00008021
,
0x8e22001c
,
0x34637654
,
0x10430002
,
0x24100002
,
0x24100001
,
0x0e000300
,
0x02003021
,
0x24020003
,
0x3c010800
,
0xa02216f8
,
0x24020002
,
0x1202000a
,
0x24020001
,
0x3c030800
,
0x8c631fd0
,
0x10620006
,
0x00000000
,
0x3c020800
,
0x94421fb8
,
0x00021400
,
0x0a0002cd
,
0xae220014
,
0x3c040800
,
0x24841fba
,
0x94820000
,
0x00021400
,
0xae220014
,
0x3c020800
,
0x8c42171c
,
0x3c03c000
,
0x3c010800
,
0xa02016f8
,
0x00431025
,
0xaf625c5c
,
0x8f625c50
,
0x30420002
,
0x10400009
,
0x00000000
,
0x2484f762
,
0x8c820000
,
0x00431025
,
0xaf625c5c
,
0x8f625c50
,
0x30420002
,
0x1440fffa
,
0x00000000
,
0x3c020800
,
0x244216e4
,
0x8c430000
,
0x24630001
,
0xac430000
,
0x8f630c14
,
0x3063000f
,
0x2c620002
,
0x1440000b
,
0x00009821
,
0x8f630c14
,
0x3c020800
,
0x8c4216b4
,
0x3063000f
,
0x24420001
,
0x3c010800
,
0xac2216b4
,
0x2c620002
,
0x1040fff7
,
0x00009821
,
0x3c024000
,
0x02421825
,
0xaf635c9c
,
0x8f625c90
,
0x30420002
,
0x1440fffc
,
0x00000000
,
0x12600003
,
0x00000000
,
0x0e000450
,
0x00000000
,
0x8fbf0020
,
0x8fb3001c
,
0x8fb20018
,
0x8fb10014
,
0x8fb00010
,
0x03e00008
,
0x27bd0028
,
0x0a0002df
,
0x00000000
,
0x8f634450
,
0x3c040800
,
0x248416e8
,
0x8c820000
,
0x00031c02
,
0x0043102b
,
0x14400007
,
0x3c038000
,
0x8c840004
,
0x8f624450
,
0x00021c02
,
0x0083102b
,
0x1040fffc
,
0x3c038000
,
0xaf634444
,
0x8f624444
,
0x00431024
,
0x1440fffd
,
0x00000000
,
0x8f624448
,
0x03e00008
,
0x3042ffff
,
0x3c024000
,
0x00822025
,
0xaf645c38
,
0x8f625c30
,
0x30420002
,
0x1440fffc
,
0x00000000
,
0x03e00008
,
0x00000000
,
0x27bdffe0
,
0x00805021
,
0x14c00017
,
0x254c0008
,
0x3c020800
,
0x8c421fd4
,
0x1040000a
,
0x2402003e
,
0x3c010800
,
0xa4221fb0
,
0x24020016
,
0x3c010800
,
0xa4221fb2
,
0x2402002a
,
0x3c010800
,
0x0a00031a
,
0xa4221fb4
,
0x95420014
,
0x3c010800
,
0xa4221fb0
,
0x8d430010
,
0x00031402
,
0x3c010800
,
0xa4221fb2
,
0x3c010800
,
0xa4231fb4
,
0x3c040800
,
0x94841fb4
,
0x3c030800
,
0x94631fb2
,
0x958d0006
,
0x3c020800
,
0x94421fb0
,
0x00832023
,
0x01a27023
,
0x3065ffff
,
0x24a20028
,
0x01824021
,
0x3082ffff
,
0x14c0001a
,
0x01025821
,
0x9562000c
,
0x3042003f
,
0x3c010800
,
0xa4221fb6
,
0x95620004
,
0x95630006
,
0x3c010800
,
0xac201fc4
,
0x3c010800
,
0xac201fc8
,
0x00021400
,
0x00431025
,
0x3c010800
,
0xac221720
,
0x95020004
,
0x3c010800
,
0xa4221724
,
0x95030002
,
0x01a51023
,
0x0043102a
,
0x10400010
,
0x24020001
,
0x3c010800
,
0x0a00034e
,
0xac221fd8
,
0x3c030800
,
0x8c631fc8
,
0x3c020800
,
0x94421724
,
0x00431021
,
0xa5020004
,
0x3c020800
,
0x94421720
,
0xa5620004
,
0x3c020800
,
0x8c421720
,
0xa5620006
,
0x3c020800
,
0x8c421fd0
,
0x3c070800
,
0x8ce71fc4
,
0x3c050800
,
0x144000c7
,
0x8ca51fc8
,
0x3c020800
,
0x94421724
,
0x00451821
,
0x3063ffff
,
0x0062182b
,
0x24020002
,
0x10c2000d
,
0x00a32823
,
0x3c020800
,
0x94421fb6
,
0x30420009
,
0x10400008
,
0x00000000
,
0x9562000c
,
0x3042fff6
,
0xa562000c
,
0x3c020800
,
0x94421fb6
,
0x30420009
,
0x00e23823
,
0x3c020800
,
0x8c421fd8
,
0x1040004b
,
0x24020002
,
0x01003021
,
0x3c020800
,
0x94421fb2
,
0x00003821
,
0xa500000a
,
0x01a21023
,
0xa5020002
,
0x3082ffff
,
0x00021042
,
0x18400008
,
0x00002821
,
0x00401821
,
0x94c20000
,
0x24e70001
,
0x00a22821
,
0x00e3102a
,
0x1440fffb
,
0x24c60002
,
0x00051c02
,
0x30a2ffff
,
0x00622821
,
0x00051402
,
0x00a22821
,
0x00a04821
,
0x00051027
,
0xa502000a
,
0x00002821
,
0x2506000c
,
0x00003821
,
0x94c20000
,
0x24e70001
,
0x00a22821
,
0x2ce20004
,
0x1440fffb
,
0x24c60002
,
0x95020002
,
0x00003821
,
0x91030009
,
0x00442023
,
0x01603021
,
0x3082ffff
,
0xa4c00010
,
0x00621821
,
0x00021042
,
0x18400010
,
0x00a32821
,
0x00404021
,
0x94c20000
,
0x24c60002
,
0x00a22821
,
0x30c2007f
,
0x14400006
,
0x24e70001
,
0x8d430000
,
0x3c02007f
,
0x3442ff80
,
0x00625024
,
0x25460008
,
0x00e8102a
,
0x1440fff3
,
0x00000000
,
0x30820001
,
0x10400005
,
0x00051c02
,
0xa0c00001
,
0x94c20000
,
0x00a22821
,
0x00051c02
,
0x30a2ffff
,
0x00622821
,
0x00051402
,
0x00a22821
,
0x0a000415
,
0x30a5ffff
,
0x14c20063
,
0x00000000
,
0x3c090800
,
0x95291fb2
,
0x95030002
,
0x01a91023
,
0x1062005d
,
0x01003021
,
0x00003821
,
0x00002821
,
0x01a91023
,
0xa5020002
,
0x3082ffff
,
0x00021042
,
0x18400008
,
0xa500000a
,
0x00401821
,
0x94c20000
,
0x24e70001
,
0x00a22821
,
0x00e3102a
,
0x1440fffb
,
0x24c60002
,
0x00051c02
,
0x30a2ffff
,
0x00622821
,
0x00051402
,
0x00a22821
,
0x00a04821
,
0x00051027
,
0xa502000a
,
0x00002821
,
0x2506000c
,
0x00003821
,
0x94c20000
,
0x24e70001
,
0x00a22821
,
0x2ce20004
,
0x1440fffb
,
0x24c60002
,
0x95020002
,
0x00003821
,
0x91030009
,
0x00442023
,
0x01603021
,
0x3082ffff
,
0xa4c00010
,
0x3c040800
,
0x94841fb4
,
0x00621821
,
0x00a32821
,
0x00051c02
,
0x30a2ffff
,
0x00622821
,
0x00051c02
,
0x3c020800
,
0x94421fb0
,
0x00a34021
,
0x00441023
,
0x00021fc2
,
0x00431021
,
0x00021043
,
0x18400010
,
0x00002821
,
0x00402021
,
0x94c20000
,
0x24c60002
,
0x00a22821
,
0x30c2007f
,
0x14400006
,
0x24e70001
,
0x8d430000
,
0x3c02007f
,
0x3442ff80
,
0x00625024
,
0x25460008
,
0x00e4102a
,
0x1440fff3
,
0x00000000
,
0x3c020800
,
0x94421fcc
,
0x00a22821
,
0x00051c02
,
0x30a2ffff
,
0x00622821
,
0x00051402
,
0x00a22821
,
0x3102ffff
,
0x00a22821
,
0x00051c02
,
0x30a2ffff
,
0x00622821
,
0x00051402
,
0x00a22821
,
0x00a02021
,
0x00051027
,
0xa5620010
,
0xad800014
,
0x0a000435
,
0xad800000
,
0x8d830010
,
0x00602021
,
0x10a00007
,
0x00034c02
,
0x01252821
,
0x00051402
,
0x30a3ffff
,
0x00432821
,
0x00051402
,
0x00a24821
,
0x00091027
,
0xa502000a
,
0x3c030800
,
0x94631fb4
,
0x3082ffff
,
0x01a21021
,
0x00432823
,
0x00a72821
,
0x00051c02
,
0x30a2ffff
,
0x00622821
,
0x00051402
,
0x00a22821
,
0x00a02021
,
0x00051027
,
0xa5620010
,
0x3082ffff
,
0x00091c00
,
0x00431025
,
0xad820010
,
0x3c020800
,
0x8c421fd4
,
0x10400002
,
0x25a2fff2
,
0xa5820034
,
0x3c020800
,
0x8c421fc8
,
0x3c030800
,
0x8c631720
,
0x24420001
,
0x3c010800
,
0xac221fc8
,
0x3c020800
,
0x8c421fc4
,
0x31c4ffff
,
0x00641821
,
0x3c010800
,
0xac231720
,
0x00441021
,
0x3c010800
,
0xac221fc4
,
0x03e00008
,
0x27bd0020
,
0x27bdffc8
,
0x3c040800
,
0x248416f8
,
0xafbf0034
,
0xafbe0030
,
0xafb7002c
,
0xafb60028
,
0xafb50024
,
0xafb40020
,
0xafb3001c
,
0xafb20018
,
0xafb10014
,
0xafb00010
,
0x90830000
,
0x24020003
,
0x146200f4
,
0x00000000
,
0x3c020800
,
0x8c421710
,
0x3c030800
,
0x8c63170c
,
0x3c1e0800
,
0x97de16f6
,
0x0043102a
,
0x104000eb
,
0x3c168000
,
0x249708c4
,
0x33d5ffff
,
0x24920018
,
0x3c020800
,
0x8c421718
,
0x104000e4
,
0x00000000
,
0x3c140800
,
0x96941fb0
,
0x3282ffff
,
0x104000d6
,
0x00008021
,
0x00409821
,
0x00008821
,
0x8f634450
,
0x3c020800
,
0x8c4216e8
,
0x00031c02
,
0x0043102b
,
0x14400008
,
0x00000000
,
0x3c040800
,
0x8c8416ec
,
0x8f624450
,
0x00021c02
,
0x0083102b
,
0x1040fffc
,
0x00000000
,
0xaf764444
,
0x8f624444
,
0x00561024
,
0x10400006
,
0x00000000
,
0x3c038000
,
0x8f624444
,
0x00431024
,
0x1440fffd
,
0x00000000
,
0x8f624448
,
0x3046ffff
,
0x10c0005f
,
0x00000000
,
0x3c090800
,
0x01314821
,
0x8d291728
,
0x9528000a
,
0x31020040
,
0x10400004
,
0x2407180c
,
0x8d22000c
,
0x2407188c
,
0xacc20018
,
0x31021000
,
0x10400004
,
0x34e32000
,
0x00081040
,
0x3042c000
,
0x00623825
,
0x31020080
,
0x54400001
,
0x34e70010
,
0x3c020800
,
0x00511021
,
0x8c421730
,
0x3c030800
,
0x00711821
,
0x8c631734
,
0x00021500
,
0x00031c00
,
0x00431025
,
0xacc20014
,
0x95240008
,
0x3202ffff
,
0x00821021
,
0x0262102a
,
0x14400002
,
0x02902823
,
0x00802821
,
0x8d220000
,
0x02058021
,
0xacc20000
,
0x8d220004
,
0x00c02021
,
0x26310010
,
0xac820004
,
0x30e2ffff
,
0xac800008
,
0xa485000e
,
0xac820010
,
0x24020305
,
0x0e000560
,
0xa482000c
,
0x3202ffff
,
0x0053102b
,
0x1440ffaf
,
0x3202ffff
,
0x0a00054c
,
0x00000000
,
0x8e420000
,
0x8e43fffc
,
0x0043102a
,
0x10400084
,
0x00000000
,
0x8e45fff0
,
0x8f644450
,
0x3c030800
,
0x8c6316e8
,
0x00051100
,
0x3c090800
,
0x01224821
,
0x8d291728
,
0x00041402
,
0x0062182b
,
0x14600008
,
0x00000000
,
0x3c030800
,
0x8c6316ec
,
0x8f624450
,
0x00021402
,
0x0062102b
,
0x1040fffc
,
0x00000000
,
0xaf764444
,
0x8f624444
,
0x00561024
,
0x10400006
,
0x00000000
,
0x3c038000
,
0x8f624444
,
0x00431024
,
0x1440fffd
,
0x00000000
,
0x8f624448
,
0x3046ffff
,
0x14c00005
,
0x00000000
,
0x8ee20000
,
0x24420001
,
0x0a000554
,
0xaee20000
,
0x9528000a
,
0x31020040
,
0x10400004
,
0x2407180c
,
0x8d22000c
,
0x2407188c
,
0xacc20018
,
0x31021000
,
0x10400004
,
0x34e32000
,
0x00081040
,
0x3042c000
,
0x00623825
,
0x00051900
,
0x3c020800
,
0x00431021
,
0x8c421730
,
0x3c010800
,
0x00230821
,
0x8c231734
,
0x00021500
,
0x00031c00
,
0x00431025
,
0xacc20014
,
0x3c030800
,
0x8c631704
,
0x95220008
,
0x00432023
,
0x3202ffff
,
0x3083ffff
,
0x00431021
,
0x02a2102a
,
0x14400002
,
0x03d02823
,
0x00802821
,
0x8e420000
,
0x30a4ffff
,
0x00441021
,
0xae420000
,
0xa4c5000e
,
0x8d220000
,
0xacc20000
,
0x8d220004
,
0x8e43fff4
,
0x00431021
,
0xacc20004
,
0x8e43fff4
,
0x95220008
,
0x00641821
,
0x0062102a
,
0x14400006
,
0x02058021
,
0x8e42fff0
,
0xae40fff4
,
0x24420001
,
0x0a000530
,
0xae42fff0
,
0xae43fff4
,
0xacc00008
,
0x3202ffff
,
0x10550003
,
0x31020004
,
0x10400006
,
0x24020305
,
0x31020080
,
0x54400001
,
0x34e70010
,
0x34e70020
,
0x24020905
,
0xa4c2000c
,
0x30e2ffff
,
0xacc20010
,
0x3c030800
,
0x8c63170c
,
0x3c020800
,
0x8c421710
,
0x54620004
,
0x3c02b49a
,
0x3c024b65
,
0x0a000548
,
0x34427654
,
0x344289ab
,
0xacc2001c
,
0x0e000560
,
0x00c02021
,
0x3202ffff
,
0x0055102b
,
0x1440ff7e
,
0x00000000
,
0x8e420000
,
0x8e43fffc
,
0x0043102a
,
0x1440ff1a
,
0x00000000
,
0x8fbf0034
,
0x8fbe0030
,
0x8fb7002c
,
0x8fb60028
,
0x8fb50024
,
0x8fb40020
,
0x8fb3001c
,
0x8fb20018
,
0x8fb10014
,
0x8fb00010
,
0x03e00008
,
0x27bd0038
,
0x27bdffe8
,
0xafbf0014
,
0xafb00010
,
0x8f624450
,
0x8f634410
,
0x0a00056f
,
0x00808021
,
0x8f626820
,
0x30422000
,
0x10400003
,
0x00000000
,
0x0e00025a
,
0x00002021
,
0x8f624450
,
0x8f634410
,
0x3042ffff
,
0x0043102b
,
0x1440fff5
,
0x00000000
,
0x8f630c14
,
0x3063000f
,
0x2c620002
,
0x1440000b
,
0x00000000
,
0x8f630c14
,
0x3c020800
,
0x8c4216b4
,
0x3063000f
,
0x24420001
,
0x3c010800
,
0xac2216b4
,
0x2c620002
,
0x1040fff7
,
0x00000000
,
0xaf705c18
,
0x8f625c10
,
0x30420002
,
0x10400009
,
0x00000000
,
0x8f626820
,
0x30422000
,
0x1040fff8
,
0x00000000
,
0x0e00025a
,
0x00002021
,
0x0a000582
,
0x00000000
,
0x8fbf0014
,
0x8fb00010
,
0x03e00008
,
0x27bd0018
,
0x00000000
,
0x00000000
};
u32
tg3TsoFwRodata
[]
=
{
0x4d61696e
,
0x43707542
,
0x00000000
,
0x00000000
,
0x74637073
,
0x6567496e
,
0x00000000
,
0x53774576
,
0x656e7430
,
0x00000000
,
0x00000000
,
0x00000000
,
0x00000000
};
#if 0 /* All zeros, dont eat up space with it. */
u32 tg3TsoFwData[] = {
0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000
};
#endif
/* tp->lock is held. */
static
int
tg3_load_tso_firmware
(
struct
tg3
*
tp
)
{
struct
fw_info
info
;
int
err
,
i
;
info
.
text_base
=
TG3_TSO_FW_TEXT_ADDR
;
info
.
text_len
=
TG3_TSO_FW_TEXT_LEN
;
info
.
text_data
=
&
tg3TsoFwText
[
0
];
info
.
rodata_base
=
TG3_TSO_FW_RODATA_ADDR
;
info
.
rodata_len
=
TG3_TSO_FW_RODATA_LEN
;
info
.
rodata_data
=
&
tg3TsoFwRodata
[
0
];
info
.
data_base
=
TG3_TSO_FW_DATA_ADDR
;
info
.
data_len
=
TG3_TSO_FW_DATA_LEN
;
info
.
data_data
=
NULL
;
err
=
tg3_load_firmware_cpu
(
tp
,
TX_CPU_BASE
,
TX_CPU_SCRATCH_BASE
,
TX_CPU_SCRATCH_SIZE
,
&
info
);
if
(
err
)
return
err
;
/* Now startup only the TX cpu. */
tw32
(
TX_CPU_BASE
+
CPU_STATE
,
0xffffffff
);
tw32
(
TX_CPU_BASE
+
CPU_PC
,
TG3_TSO_FW_TEXT_ADDR
);
/* Flush posted writes. */
tr32
(
TX_CPU_BASE
+
CPU_PC
);
for
(
i
=
0
;
i
<
5
;
i
++
)
{
if
(
tr32
(
TX_CPU_BASE
+
CPU_PC
)
==
TG3_TSO_FW_TEXT_ADDR
)
break
;
tw32
(
TX_CPU_BASE
+
CPU_STATE
,
0xffffffff
);
tw32
(
TX_CPU_BASE
+
CPU_MODE
,
CPU_MODE_HALT
);
tw32
(
TX_CPU_BASE
+
CPU_PC
,
TG3_TSO_FW_TEXT_ADDR
);
/* Flush posted writes. */
tr32
(
TX_CPU_BASE
+
CPU_PC
);
udelay
(
1000
);
}
if
(
i
>=
5
)
{
printk
(
KERN_ERR
PFX
"tg3_load_tso_firmware fails for %s "
"to set TX CPU PC, is %08x should be %08x
\n
"
,
tp
->
dev
->
name
,
tr32
(
TX_CPU_BASE
+
CPU_PC
),
TG3_TSO_FW_TEXT_ADDR
);
return
-
ENODEV
;
}
tw32
(
TX_CPU_BASE
+
CPU_STATE
,
0xffffffff
);
tw32
(
TX_CPU_BASE
+
CPU_MODE
,
0x00000000
);
/* Flush posted writes. */
tr32
(
TX_CPU_BASE
+
CPU_MODE
);
return
0
;
}
#endif
/* TG3_DO_TSO != 0 */
/* tp->lock is held. */
static
void
__tg3_set_mac_addr
(
struct
tg3
*
tp
)
{
...
...
@@ -3294,6 +3887,8 @@ static int tg3_reset_hw(struct tg3 *tp)
tg3_disable_ints
(
tp
);
tg3_stop_fw
(
tp
);
if
(
tp
->
tg3_flags
&
TG3_FLAG_INIT_COMPLETE
)
{
err
=
tg3_abort_hw
(
tp
);
if
(
err
)
...
...
@@ -3311,6 +3906,8 @@ static int tg3_reset_hw(struct tg3 *tp)
tw32
(
MAC_MODE
,
tp
->
mac_mode
);
}
else
tw32
(
MAC_MODE
,
0
);
tr32
(
MAC_MODE
);
udelay
(
40
);
/* Wait for firmware initialization to complete. */
for
(
i
=
0
;
i
<
100000
;
i
++
)
{
...
...
@@ -3326,6 +3923,13 @@ static int tg3_reset_hw(struct tg3 *tp)
return
-
ENODEV
;
}
if
(
tp
->
tg3_flags
&
TG3_FLAG_ENABLE_ASF
)
tg3_write_mem
(
tp
,
NIC_SRAM_FW_DRV_STATE_MBOX
,
DRV_STATE_START
);
else
tg3_write_mem
(
tp
,
NIC_SRAM_FW_DRV_STATE_MBOX
,
DRV_STATE_SUSPEND
);
/* This works around an issue with Athlon chipsets on
* B3 tigon3 silicon. This bit has no effect on any
* other revision.
...
...
@@ -3333,6 +3937,14 @@ static int tg3_reset_hw(struct tg3 *tp)
val
=
tr32
(
TG3PCI_CLOCK_CTRL
);
val
|=
CLOCK_CTRL_DELAY_PCI_GRANT
;
tw32
(
TG3PCI_CLOCK_CTRL
,
val
);
tr32
(
TG3PCI_CLOCK_CTRL
);
if
(
tp
->
pci_chip_rev_id
==
CHIPREV_ID_5704_A0
&&
(
tp
->
tg3_flags
&
TG3_FLAG_PCIX_MODE
))
{
val
=
tr32
(
TG3PCI_PCISTATE
);
val
|=
PCISTATE_RETRY_SAME_DMA
;
tw32
(
TG3PCI_PCISTATE
,
val
);
}
/* Clear statistics/status block in chip, and status block in ram. */
for
(
i
=
NIC_SRAM_STATS_BLK
;
...
...
@@ -3371,7 +3983,10 @@ static int tg3_reset_hw(struct tg3 *tp)
/* Initialize MBUF/DESC pool. */
tw32
(
BUFMGR_MB_POOL_ADDR
,
NIC_SRAM_MBUF_POOL_BASE
);
tw32
(
BUFMGR_MB_POOL_SIZE
,
NIC_SRAM_MBUF_POOL_SIZE
);
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5704
)
tw32
(
BUFMGR_MB_POOL_SIZE
,
NIC_SRAM_MBUF_POOL_SIZE64
);
else
tw32
(
BUFMGR_MB_POOL_SIZE
,
NIC_SRAM_MBUF_POOL_SIZE96
);
tw32
(
BUFMGR_DMA_DESC_POOL_ADDR
,
NIC_SRAM_DMA_DESC_POOL_BASE
);
tw32
(
BUFMGR_DMA_DESC_POOL_SIZE
,
NIC_SRAM_DMA_DESC_POOL_SIZE
);
...
...
@@ -3491,6 +4106,8 @@ static int tg3_reset_hw(struct tg3 *tp)
tp
->
tx_cons
=
0
;
tw32_mailbox
(
MAILBOX_SNDHOST_PROD_IDX_0
+
TG3_64BIT_REG_LOW
,
0
);
tw32_mailbox
(
MAILBOX_SNDNIC_PROD_IDX_0
+
TG3_64BIT_REG_LOW
,
0
);
if
(
tp
->
tg3_flags
&
TG3_FLAG_MBOX_WRITE_REORDER
)
tr32
(
MAILBOX_SNDNIC_PROD_IDX_0
+
TG3_64BIT_REG_LOW
);
if
(
tp
->
tg3_flags
&
TG3_FLAG_HOST_TXDS
)
{
tg3_set_bdinfo
(
tp
,
NIC_SRAM_SEND_RCB
,
...
...
@@ -3512,6 +4129,8 @@ static int tg3_reset_hw(struct tg3 *tp)
tp
->
rx_rcb_ptr
=
0
;
tw32_mailbox
(
MAILBOX_RCVRET_CON_IDX_0
+
TG3_64BIT_REG_LOW
,
0
);
if
(
tp
->
tg3_flags
&
TG3_FLAG_MBOX_WRITE_REORDER
)
tr32
(
MAILBOX_RCVRET_CON_IDX_0
+
TG3_64BIT_REG_LOW
);
tg3_set_bdinfo
(
tp
,
NIC_SRAM_RCV_RET_RCB
,
tp
->
rx_rcb_mapping
,
...
...
@@ -3522,10 +4141,14 @@ static int tg3_reset_hw(struct tg3 *tp)
tp
->
rx_std_ptr
=
tp
->
rx_pending
;
tw32_mailbox
(
MAILBOX_RCV_STD_PROD_IDX
+
TG3_64BIT_REG_LOW
,
tp
->
rx_std_ptr
);
if
(
tp
->
tg3_flags
&
TG3_FLAG_MBOX_WRITE_REORDER
)
tr32
(
MAILBOX_RCV_STD_PROD_IDX
+
TG3_64BIT_REG_LOW
);
#if TG3_MINI_RING_WORKS
tp
->
rx_mini_ptr
=
tp
->
rx_mini_pending
;
tw32_mailbox
(
MAILBOX_RCV_MINI_PROD_IDX
+
TG3_64BIT_REG_LOW
,
tp
->
rx_mini_ptr
);
if
(
tp
->
tg3_flags
&
TG3_FLAG_MBOX_WRITE_REORDER
)
tr32
(
MAILBOX_RCV_MINI_PROD_IDX
+
TG3_64BIT_REG_LOW
);
#endif
if
(
tp
->
tg3_flags
&
TG3_FLAG_JUMBO_ENABLE
)
...
...
@@ -3534,6 +4157,8 @@ static int tg3_reset_hw(struct tg3 *tp)
tp
->
rx_jumbo_ptr
=
0
;
tw32_mailbox
(
MAILBOX_RCV_JUMBO_PROD_IDX
+
TG3_64BIT_REG_LOW
,
tp
->
rx_jumbo_ptr
);
if
(
tp
->
tg3_flags
&
TG3_FLAG_MBOX_WRITE_REORDER
)
tr32
(
MAILBOX_RCV_JUMBO_PROD_IDX
+
TG3_64BIT_REG_LOW
);
/* Initialize MAC address and backoff seed. */
__tg3_set_mac_addr
(
tp
);
...
...
@@ -3601,25 +4226,53 @@ static int tg3_reset_hw(struct tg3 *tp)
tp
->
mac_mode
=
MAC_MODE_TXSTAT_ENABLE
|
MAC_MODE_RXSTAT_ENABLE
|
MAC_MODE_TDE_ENABLE
|
MAC_MODE_RDE_ENABLE
|
MAC_MODE_FHDE_ENABLE
;
tw32
(
MAC_MODE
,
tp
->
mac_mode
|
MAC_MODE_RXSTAT_CLEAR
|
MAC_MODE_TXSTAT_CLEAR
);
tr32
(
MAC_MODE
);
udelay
(
40
);
tp
->
grc_local_ctrl
=
GRC_LCLCTRL_INT_ON_ATTN
|
GRC_LCLCTRL_GPIO_OE1
|
GRC_LCLCTRL_GPIO_OUTPUT1
|
GRC_LCLCTRL_AUTO_SEEPROM
;
tp
->
grc_local_ctrl
=
GRC_LCLCTRL_INT_ON_ATTN
|
GRC_LCLCTRL_AUTO_SEEPROM
;
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5700
)
tp
->
grc_local_ctrl
|=
(
GRC_LCLCTRL_GPIO_OE1
|
GRC_LCLCTRL_GPIO_OUTPUT1
);
tw32
(
GRC_LOCAL_CTRL
,
tp
->
grc_local_ctrl
);
tr32
(
GRC_LOCAL_CTRL
);
udelay
(
100
);
tw32_mailbox
(
MAILBOX_INTERRUPT_0
+
TG3_64BIT_REG_LOW
,
0
);
tr32
(
MAILBOX_INTERRUPT_0
);
tw32
(
DMAC_MODE
,
DMAC_MODE_ENABLE
);
tr32
(
DMAC_MODE
);
udelay
(
40
);
tw32
(
WDMAC_MODE
,
(
WDMAC_MODE_ENABLE
|
WDMAC_MODE_TGTABORT_ENAB
|
WDMAC_MODE_MSTABORT_ENAB
|
WDMAC_MODE_PARITYERR_ENAB
|
WDMAC_MODE_ADDROFLOW_ENAB
|
WDMAC_MODE_FIFOOFLOW_ENAB
|
WDMAC_MODE_FIFOURUN_ENAB
|
WDMAC_MODE_FIFOOREAD_ENAB
|
WDMAC_MODE_LNGREAD_ENAB
));
tw32
(
RDMAC_MODE
,
(
RDMAC_MODE_ENABLE
|
RDMAC_MODE_TGTABORT_ENAB
|
RDMAC_MODE_MSTABORT_ENAB
|
RDMAC_MODE_PARITYERR_ENAB
|
RDMAC_MODE_ADDROFLOW_ENAB
|
RDMAC_MODE_FIFOOFLOW_ENAB
|
RDMAC_MODE_FIFOURUN_ENAB
|
RDMAC_MODE_FIFOOREAD_ENAB
|
RDMAC_MODE_LNGREAD_ENAB
));
tr32
(
WDMAC_MODE
);
udelay
(
40
);
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5704
&&
(
tp
->
tg3_flags
&
TG3_FLAG_PCIX_MODE
))
{
val
=
tr32
(
TG3PCI_X_CAPS
);
val
&=
~
(
PCIX_CAPS_SPLIT_MASK
|
PCIX_CAPS_BURST_MASK
);
val
|=
(
PCIX_CAPS_MAX_BURST_5704
<<
PCIX_CAPS_BURST_SHIFT
);
if
(
tp
->
tg3_flags
&
TG3_FLAG_SPLIT_MODE
)
val
|=
(
tp
->
split_mode_max_reqs
<<
PCIX_CAPS_SPLIT_SHIFT
);
tw32
(
TG3PCI_X_CAPS
,
val
);
}
val
=
(
RDMAC_MODE_ENABLE
|
RDMAC_MODE_TGTABORT_ENAB
|
RDMAC_MODE_MSTABORT_ENAB
|
RDMAC_MODE_PARITYERR_ENAB
|
RDMAC_MODE_ADDROFLOW_ENAB
|
RDMAC_MODE_FIFOOFLOW_ENAB
|
RDMAC_MODE_FIFOURUN_ENAB
|
RDMAC_MODE_FIFOOREAD_ENAB
|
RDMAC_MODE_LNGREAD_ENAB
);
if
(
tp
->
tg3_flags
&
TG3_FLAG_SPLIT_MODE
)
val
|=
RDMAC_MODE_SPLIT_ENABLE
;
tw32
(
RDMAC_MODE
,
val
);
tr32
(
RDMAC_MODE
);
udelay
(
40
);
tw32
(
RCVDCC_MODE
,
RCVDCC_MODE_ENABLE
|
RCVDCC_MODE_ATTN_ENABLE
);
tw32
(
MBFREE_MODE
,
MBFREE_MODE_ENABLE
);
...
...
@@ -3637,10 +4290,21 @@ static int tg3_reset_hw(struct tg3 *tp)
return
err
;
}
#if TG3_DO_TSO != 0
err
=
tg3_load_tso_firmware
(
tp
);
if
(
err
)
return
err
;
#endif
tp
->
tx_mode
=
TX_MODE_ENABLE
;
tw32
(
MAC_TX_MODE
,
tp
->
tx_mode
);
tr32
(
MAC_TX_MODE
);
udelay
(
100
);
tp
->
rx_mode
=
RX_MODE_ENABLE
;
tw32
(
MAC_RX_MODE
,
tp
->
rx_mode
);
tr32
(
MAC_RX_MODE
);
udelay
(
10
);
if
(
tp
->
link_config
.
phy_is_low_power
)
{
tp
->
link_config
.
phy_is_low_power
=
0
;
...
...
@@ -3651,11 +4315,17 @@ static int tg3_reset_hw(struct tg3 *tp)
tp
->
mi_mode
=
MAC_MI_MODE_BASE
;
tw32
(
MAC_MI_MODE
,
tp
->
mi_mode
);
tr32
(
MAC_MI_MODE
);
udelay
(
40
);
tw32
(
MAC_LED_CTRL
,
0
);
tw32
(
MAC_MI_STAT
,
MAC_MI_STAT_LNKSTAT_ATTN_ENAB
);
tw32
(
MAC_RX_MODE
,
RX_MODE_RESET
);
tr32
(
MAC_RX_MODE
);
udelay
(
10
);
tw32
(
MAC_RX_MODE
,
tp
->
rx_mode
);
tr32
(
MAC_RX_MODE
);
udelay
(
10
);
if
(
tp
->
pci_chip_rev_id
==
CHIPREV_ID_5703_A1
)
tw32
(
MAC_SERDES_CFG
,
0x616000
);
...
...
@@ -3738,7 +4408,7 @@ static void tg3_timer(unsigned long __opaque)
tw32
(
GRC_LOCAL_CTRL
,
tp
->
grc_local_ctrl
|
GRC_LCLCTRL_SETINT
);
}
else
{
tw32
(
HOSTCC_MODE
,
tw32
(
HOSTCC_MODE
,
tp
->
coalesce_mode
|
(
HOSTCC_MODE_ENABLE
|
HOSTCC_MODE_NOW
));
}
...
...
@@ -3781,8 +4451,11 @@ static void tg3_timer(unsigned long __opaque)
tw32
(
MAC_MODE
,
(
tp
->
mac_mode
&
~
MAC_MODE_PORT_MODE_MASK
));
tr32
(
MAC_MODE
);
udelay
(
40
);
tw32
(
MAC_MODE
,
tp
->
mac_mode
);
tr32
(
MAC_MODE
);
udelay
(
40
);
tg3_setup_phy
(
tp
);
}
}
...
...
@@ -3790,6 +4463,21 @@ static void tg3_timer(unsigned long __opaque)
tp
->
timer_counter
=
tp
->
timer_multiplier
;
}
/* Heartbeat is only sent once every 120 seconds. */
if
(
!--
tp
->
asf_counter
)
{
if
(
tp
->
tg3_flags
&
TG3_FLAG_ENABLE_ASF
)
{
u32
val
;
tg3_write_mem
(
tp
,
NIC_SRAM_FW_CMD_MBOX
,
FWCMD_NICDRV_ALIVE
);
tg3_write_mem
(
tp
,
NIC_SRAM_FW_CMD_LEN_MBOX
,
4
);
tg3_write_mem
(
tp
,
NIC_SRAM_FW_CMD_DATA_MBOX
,
3
);
val
=
tr32
(
GRC_RX_CPU_EVENT
);
val
|=
(
1
<<
14
);
tw32
(
GRC_RX_CPU_EVENT
,
val
);
}
tp
->
asf_counter
=
tp
->
asf_multiplier
;
}
spin_unlock
(
&
tp
->
tx_lock
);
spin_unlock_irq
(
&
tp
->
lock
);
...
...
@@ -3838,6 +4526,7 @@ static int tg3_open(struct net_device *dev)
}
else
{
tp
->
timer_offset
=
HZ
/
10
;
tp
->
timer_counter
=
tp
->
timer_multiplier
=
10
;
tp
->
asf_counter
=
tp
->
asf_multiplier
=
(
10
*
120
);
init_timer
(
&
tp
->
timer
);
tp
->
timer
.
expires
=
jiffies
+
tp
->
timer_offset
;
...
...
@@ -4272,10 +4961,10 @@ static inline u32 calc_crc(unsigned char *buf, int len)
static
void
tg3_set_multi
(
struct
tg3
*
tp
,
unsigned
int
accept_all
)
{
/* accept or reject all multicast frames */
tw32
(
MAC_HASH_REG_0
,
accept_all
?
0xffffffff
:
0
);
tw32
(
MAC_HASH_REG_1
,
accept_all
?
0xffffffff
:
0
);
tw32
(
MAC_HASH_REG_2
,
accept_all
?
0xffffffff
:
0
);
tw32
(
MAC_HASH_REG_3
,
accept_all
?
0xffffffff
:
0
);
tw32
(
MAC_HASH_REG_0
,
accept_all
?
0xffffffff
:
0
);
tw32
(
MAC_HASH_REG_1
,
accept_all
?
0xffffffff
:
0
);
tw32
(
MAC_HASH_REG_2
,
accept_all
?
0xffffffff
:
0
);
tw32
(
MAC_HASH_REG_3
,
accept_all
?
0xffffffff
:
0
);
}
static
void
__tg3_set_rx_mode
(
struct
net_device
*
dev
)
...
...
@@ -4283,7 +4972,17 @@ static void __tg3_set_rx_mode(struct net_device *dev)
struct
tg3
*
tp
=
dev
->
priv
;
u32
rx_mode
;
rx_mode
=
tp
->
rx_mode
&
~
RX_MODE_PROMISC
;
rx_mode
=
tp
->
rx_mode
&
~
(
RX_MODE_PROMISC
|
RX_MODE_KEEP_VLAN_TAG
);
#if TG3_VLAN_TAG_USED
if
(
!
tp
->
vlgrp
)
rx_mode
|=
RX_MODE_KEEP_VLAN_TAG
;
#else
/* By definition, VLAN is disabled always in this
* case.
*/
rx_mode
|=
RX_MODE_KEEP_VLAN_TAG
;
#endif
if
(
dev
->
flags
&
IFF_PROMISC
)
{
/* Promiscuous mode. */
...
...
@@ -4313,15 +5012,17 @@ static void __tg3_set_rx_mode(struct net_device *dev)
mc_filter
[
regidx
]
|=
(
1
<<
bit
);
}
tw32
(
MAC_HASH_REG_0
,
mc_filter
[
0
]);
tw32
(
MAC_HASH_REG_1
,
mc_filter
[
1
]);
tw32
(
MAC_HASH_REG_2
,
mc_filter
[
2
]);
tw32
(
MAC_HASH_REG_3
,
mc_filter
[
3
]);
tw32
(
MAC_HASH_REG_0
,
mc_filter
[
0
]);
tw32
(
MAC_HASH_REG_1
,
mc_filter
[
1
]);
tw32
(
MAC_HASH_REG_2
,
mc_filter
[
2
]);
tw32
(
MAC_HASH_REG_3
,
mc_filter
[
3
]);
}
if
(
rx_mode
!=
tp
->
rx_mode
)
{
tp
->
rx_mode
=
rx_mode
;
tw32
(
MAC_RX_MODE
,
rx_mode
);
tw32
(
MAC_RX_MODE
,
rx_mode
);
tr32
(
MAC_RX_MODE
);
udelay
(
10
);
}
}
...
...
@@ -4837,7 +5538,12 @@ static void tg3_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
spin_lock_irq
(
&
tp
->
lock
);
spin_lock
(
&
tp
->
tx_lock
);
tp
->
vlgrp
=
grp
;
/* Update RX_MODE_KEEP_VLAN_TAG bit in RX_MODE register. */
__tg3_set_rx_mode
(
dev
);
spin_unlock
(
&
tp
->
tx_lock
);
spin_unlock_irq
(
&
tp
->
lock
);
}
...
...
@@ -4872,6 +5578,7 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
/* Enable seeprom accesses. */
tw32
(
GRC_LOCAL_CTRL
,
tr32
(
GRC_LOCAL_CTRL
)
|
GRC_LCLCTRL_AUTO_SEEPROM
);
tr32
(
GRC_LOCAL_CTRL
);
udelay
(
100
);
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
!=
ASIC_REV_5700
&&
...
...
@@ -5079,11 +5786,14 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
eeprom_led_mode
=
led_mode_auto
;
break
;
};
}
if
((
tp
->
pci_chip_rev_id
==
CHIPREV_ID_5703_A1
||
tp
->
pci_chip_rev_id
==
CHIPREV_ID_5703_A2
)
&&
(
nic_cfg
&
NIC_SRAM_DATA_CFG_EEPROM_WP
))
tp
->
tg3_flags
|=
TG3_FLAG_EEPROM_WRITE_PROT
;
err
=
tg3_phy_reset
(
tp
,
0
);
if
(
err
)
return
err
;
if
(
nic_cfg
&
NIC_SRAM_DATA_CFG_ASF_ENABLE
)
tp
->
tg3_flags
|=
TG3_FLAG_ENABLE_ASF
;
}
/* Now read the physical PHY_ID from the chip and verify
* that it is sane. If it doesn't look good, we fall back
...
...
@@ -5114,30 +5824,24 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
}
}
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5703
)
{
tg3_writephy
(
tp
,
MII_TG3_AUX_CTRL
,
0x0c00
);
tg3_writephy
(
tp
,
MII_TG3_DSP_ADDRESS
,
0x201f
);
tg3_writephy
(
tp
,
MII_TG3_DSP_RW_PORT
,
0x2aaa
);
}
err
=
tg3_phy_reset
(
tp
,
1
);
if
(
err
)
return
err
;
if
(
tp
->
pci_chip_rev_id
==
CHIPREV_ID_5701_A0
||
tp
->
pci_chip_rev_id
==
CHIPREV_ID_5701_B0
)
tp
->
tg3_flags
|=
TG3_FLAG_PHY_RESET_ON_INIT
;
if
(
tp
->
tg3_flags
&
TG3_FLAG_PHY_RESET_ON_INIT
)
{
tp
->
pci_chip_rev_id
==
CHIPREV_ID_5701_B0
)
{
u32
mii_tg3_ctrl
;
err
=
tg3_phy_reset
(
tp
,
1
);
if
(
err
)
return
err
;
/* These chips, when reset, only advertise 10Mb capabilities.
* Fix that.
/* These chips, when reset, only advertise 10Mb
* capabilities. Fix that.
*/
err
=
tg3_writephy
(
tp
,
MII_ADVERTISE
,
(
ADVERTISE_CSMA
|
ADVERTISE_10HALF
|
ADVERTISE_10FULL
|
ADVERTISE_100HALF
|
ADVERTISE_100FULL
));
ADVERTISE_PAUSE_CAP
|
ADVERTISE_10HALF
|
ADVERTISE_10FULL
|
ADVERTISE_100HALF
|
ADVERTISE_100FULL
));
mii_tg3_ctrl
=
(
MII_TG3_CTRL_ADV_1000_HALF
|
MII_TG3_CTRL_ADV_1000_FULL
|
MII_TG3_CTRL_AS_MASTER
|
...
...
@@ -5150,6 +5854,22 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
(
BMCR_ANRESTART
|
BMCR_ANENABLE
));
}
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5703
)
{
tg3_writephy
(
tp
,
MII_TG3_AUX_CTRL
,
0x0c00
);
tg3_writephy
(
tp
,
MII_TG3_DSP_ADDRESS
,
0x201f
);
tg3_writephy
(
tp
,
MII_TG3_DSP_RW_PORT
,
0x2aaa
);
}
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5704
)
{
tg3_writephy
(
tp
,
0x1c
,
0x8d68
);
tg3_writephy
(
tp
,
0x1c
,
0x8d68
);
}
/* Enable Ethernet@WireSpeed */
tg3_writephy
(
tp
,
MII_TG3_AUX_CTRL
,
0x7007
);
tg3_readphy
(
tp
,
MII_TG3_AUX_CTRL
,
&
val
);
tg3_writephy
(
tp
,
MII_TG3_AUX_CTRL
,
(
val
|
(
1
<<
15
)
|
(
1
<<
4
)));
if
(
!
err
&&
((
tp
->
phy_id
&
PHY_ID_MASK
)
==
PHY_ID_BCM5401
))
{
err
=
tg3_init_5401phy_dsp
(
tp
);
}
...
...
@@ -5247,6 +5967,20 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
u16
pci_cmd
;
int
err
;
/* If we have an AMD 762 or Intel ICH/ICH0 chipset, write
* reordering to the mailbox registers done by the host
* controller can cause major troubles. We read back from
* every mailbox register write to force the writes to be
* posted to the chip in order.
*/
if
(
pci_find_device
(
PCI_VENDOR_ID_INTEL
,
PCI_DEVICE_ID_INTEL_82801AA_8
,
NULL
)
||
pci_find_device
(
PCI_VENDOR_ID_INTEL
,
PCI_DEVICE_ID_INTEL_82801AB_8
,
NULL
)
||
pci_find_device
(
PCI_VENDOR_ID_AMD
,
PCI_DEVICE_ID_AMD_FE_GATE_700C
,
NULL
))
tp
->
tg3_flags
|=
TG3_FLAG_MBOX_WRITE_REORDER
;
/* Force memory write invalidate off. If we leave it on,
* then on 5700_BX chips we have to enable a workaround.
* The workaround is to set the TG3PCI_DMA_RW_CTRL boundry
...
...
@@ -5258,12 +5992,24 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
pci_cmd
&=
~
PCI_COMMAND_INVALIDATE
;
pci_write_config_word
(
tp
->
pdev
,
PCI_COMMAND
,
pci_cmd
);
/* It is absolutely critical that TG3PCI_MISC_HOST_CTRL
* has the register indirect write enable bit set before
* we try to access any of the MMIO registers. It is also
* critical that the PCI-X hw workaround situation is decided
* before that as well.
*/
pci_read_config_dword
(
tp
->
pdev
,
TG3PCI_MISC_HOST_CTRL
,
&
misc_ctrl_reg
);
tp
->
pci_chip_rev_id
=
(
misc_ctrl_reg
>>
MISC_HOST_CTRL_CHIPREV_SHIFT
);
/* Initialize misc host control in PCI block. */
tp
->
misc_host_ctrl
|=
(
misc_ctrl_reg
&
MISC_HOST_CTRL_CHIPREV
);
pci_write_config_dword
(
tp
->
pdev
,
TG3PCI_MISC_HOST_CTRL
,
tp
->
misc_host_ctrl
);
pci_read_config_dword
(
tp
->
pdev
,
TG3PCI_CACHELINESZ
,
&
cacheline_sz_reg
);
...
...
@@ -5377,14 +6123,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
GET_CHIP_REV
(
tp
->
pci_chip_rev_id
)
!=
CHIPREV_5700_BX
)
tp
->
coalesce_mode
|=
HOSTCC_MODE_32BYTE
;
/* Initialize misc host control in PCI block. */
tp
->
misc_host_ctrl
|=
(
misc_ctrl_reg
&
MISC_HOST_CTRL_CHIPREV
);
pci_write_config_dword
(
tp
->
pdev
,
TG3PCI_MISC_HOST_CTRL
,
tp
->
misc_host_ctrl
);
/* Initialize MAC MI mode, polling disabled. */
tw32
(
MAC_MI_MODE
,
tp
->
mi_mode
);
tr32
(
MAC_MI_MODE
);
udelay
(
40
);
/* Initialize data/descriptor byte/word swapping. */
...
...
@@ -5439,9 +6180,16 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
grc_misc_cfg
!=
GRC_MISC_CFG_BOARD_ID_5702FE
&&
grc_misc_cfg
!=
GRC_MISC_CFG_BOARD_ID_5703
&&
grc_misc_cfg
!=
GRC_MISC_CFG_BOARD_ID_5703S
&&
grc_misc_cfg
!=
GRC_MISC_CFG_BOARD_ID_5704
&&
grc_misc_cfg
!=
GRC_MISC_CFG_BOARD_ID_AC91002A1
)
return
-
ENODEV
;
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5704
&&
grc_misc_cfg
==
GRC_MISC_CFG_BOARD_ID_5704CIOBE
)
{
tp
->
tg3_flags
|=
TG3_FLAG_SPLIT_MODE
;
tp
->
split_mode_max_reqs
=
SPLIT_MODE_5704_MAX_REQ
;
}
/* ROFL, you should see Broadcom's driver code implementing
* this, stuff like "if (a || b)" where a and b are always
* mutually exclusive. DaveM finds like 6 bugs today, hello!
...
...
@@ -5520,13 +6268,23 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
(
tp
->
tg3_flags
&
TG3_FLAG_PCIX_MODE
)
!=
0
)
tp
->
rx_offset
=
0
;
/* By default, disable wake-on-lan. User can change this
* using ETHTOOL_SWOL.
*/
tp
->
tg3_flags
&=
~
TG3_FLAG_WOL_ENABLE
;
return
err
;
}
static
int
__devinit
tg3_get_device_address
(
struct
tg3
*
tp
)
{
struct
net_device
*
dev
=
tp
->
dev
;
u32
hi
,
lo
;
u32
hi
,
lo
,
mac_offset
;
if
(
PCI_FUNC
(
tp
->
pdev
->
devfn
)
==
0
)
mac_offset
=
0x7c
;
else
mac_offset
=
0xcc
;
/* First try to get it from MAC address mailbox. */
tg3_read_mem
(
tp
,
NIC_SRAM_MAC_ADDR_HIGH_MBOX
,
&
hi
);
...
...
@@ -5541,8 +6299,8 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
dev
->
dev_addr
[
5
]
=
(
lo
>>
0
)
&
0xff
;
}
/* Next, try NVRAM. */
else
if
(
!
tg3_nvram_read
(
tp
,
0x7c
,
&
hi
)
&&
!
tg3_nvram_read
(
tp
,
0x80
,
&
lo
))
{
else
if
(
!
tg3_nvram_read
(
tp
,
mac_offset
+
0
,
&
hi
)
&&
!
tg3_nvram_read
(
tp
,
mac_offset
+
4
,
&
lo
))
{
dev
->
dev_addr
[
0
]
=
((
hi
>>
16
)
&
0xff
);
dev
->
dev_addr
[
1
]
=
((
hi
>>
24
)
&
0xff
);
dev
->
dev_addr
[
2
]
=
((
lo
>>
0
)
&
0xff
);
...
...
@@ -5593,11 +6351,21 @@ static int __devinit tg3_do_test_dma(struct tg3 *tp, u32 *buf, dma_addr_t buf_dm
if
(
to_device
)
{
test_desc
.
cqid_sqid
=
(
13
<<
8
)
|
2
;
tw32
(
RDMAC_MODE
,
RDMAC_MODE_RESET
);
tr32
(
RDMAC_MODE
);
udelay
(
40
);
tw32
(
RDMAC_MODE
,
RDMAC_MODE_ENABLE
);
tr32
(
RDMAC_MODE
);
udelay
(
40
);
}
else
{
test_desc
.
cqid_sqid
=
(
16
<<
8
)
|
7
;
tw32
(
WDMAC_MODE
,
WDMAC_MODE_RESET
);
tr32
(
WDMAC_MODE
);
udelay
(
40
);
tw32
(
WDMAC_MODE
,
WDMAC_MODE_ENABLE
);
tr32
(
WDMAC_MODE
);
udelay
(
40
);
}
test_desc
.
flags
=
0x00000004
;
...
...
@@ -5660,16 +6428,26 @@ static int __devinit tg3_test_dma(struct tg3 *tp)
(
0x7
<<
DMA_RWCTRL_READ_WATER_SHIFT
)
|
(
0x0f
<<
DMA_RWCTRL_MIN_DMA_SHIFT
);
}
else
{
tp
->
dma_rwctrl
=
(
0x7
<<
DMA_RWCTRL_PCI_WRITE_CMD_SHIFT
)
|
(
0x6
<<
DMA_RWCTRL_PCI_READ_CMD_SHIFT
)
|
(
0x3
<<
DMA_RWCTRL_WRITE_WATER_SHIFT
)
|
(
0x3
<<
DMA_RWCTRL_READ_WATER_SHIFT
)
|
(
0x0f
<<
DMA_RWCTRL_MIN_DMA_SHIFT
);
if
(
GET_ASIC_REV
(
tp
->
pci_chip_rev_id
)
==
ASIC_REV_5704
)
tp
->
dma_rwctrl
=
(
0x7
<<
DMA_RWCTRL_PCI_WRITE_CMD_SHIFT
)
|
(
0x6
<<
DMA_RWCTRL_PCI_READ_CMD_SHIFT
)
|
(
0x3
<<
DMA_RWCTRL_WRITE_WATER_SHIFT
)
|
(
0x7
<<
DMA_RWCTRL_READ_WATER_SHIFT
)
|
(
0x00
<<
DMA_RWCTRL_MIN_DMA_SHIFT
);
else
tp
->
dma_rwctrl
=
(
0x7
<<
DMA_RWCTRL_PCI_WRITE_CMD_SHIFT
)
|
(
0x6
<<
DMA_RWCTRL_PCI_READ_CMD_SHIFT
)
|
(
0x3
<<
DMA_RWCTRL_WRITE_WATER_SHIFT
)
|
(
0x3
<<
DMA_RWCTRL_READ_WATER_SHIFT
)
|
(
0x0f
<<
DMA_RWCTRL_MIN_DMA_SHIFT
);
/* Wheee, some more chip bugs... */
if
(
tp
->
pci_chip_rev_id
==
CHIPREV_ID_5703_A1
||
tp
->
pci_chip_rev_id
==
CHIPREV_ID_5703_A2
)
tp
->
pci_chip_rev_id
==
CHIPREV_ID_5703_A2
||
tp
->
pci_chip_rev_id
==
CHIPREV_ID_5703_A3
||
tp
->
pci_chip_rev_id
==
CHIPREV_ID_5704_A0
)
tp
->
dma_rwctrl
|=
DMA_RWCTRL_ONE_DMA
;
}
...
...
@@ -5844,6 +6622,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp)
case
PHY_ID_BCM5411
:
return
"5411"
;
case
PHY_ID_BCM5701
:
return
"5701"
;
case
PHY_ID_BCM5703
:
return
"5703"
;
case
PHY_ID_BCM5704
:
return
"5704"
;
case
PHY_ID_BCM8002
:
return
"8002"
;
case
PHY_ID_SERDES
:
return
"serdes"
;
default:
return
"unknown"
;
...
...
@@ -5925,6 +6704,9 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
dev
->
vlan_rx_register
=
tg3_vlan_rx_register
;
dev
->
vlan_rx_kill_vid
=
tg3_vlan_rx_kill_vid
;
#endif
#if TG3_DO_TSO != 0
dev
->
features
|=
NETIF_F_TSO
;
#endif
tp
=
dev
->
priv
;
tp
->
pdev
=
pdev
;
...
...
drivers/net/tg3.h
View file @
d038b8c5
...
...
@@ -58,6 +58,11 @@
#define TG3PCI_MAX_LAT 0x0000003f
#define TG3PCI_X_CAPS 0x00000040
#define PCIX_CAPS_RELAXED_ORDERING 0x00020000
#define PCIX_CAPS_SPLIT_MASK 0x00700000
#define PCIX_CAPS_SPLIT_SHIFT 20
#define PCIX_CAPS_BURST_MASK 0x000c0000
#define PCIX_CAPS_BURST_SHIFT 18
#define PCIX_CAPS_MAX_BURST_5704 2
#define TG3PCI_PM_CAP_PTR 0x00000041
#define TG3PCI_X_COMMAND 0x00000042
#define TG3PCI_X_STATUS 0x00000044
...
...
@@ -109,10 +114,13 @@
#define CHIPREV_ID_5703_A0 0x1000
#define CHIPREV_ID_5703_A1 0x1001
#define CHIPREV_ID_5703_A2 0x1002
#define CHIPREV_ID_5703_A3 0x1003
#define CHIPREV_ID_5704_A0 0x2000
#define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12)
#define ASIC_REV_5700 0x07
#define ASIC_REV_5701 0x00
#define ASIC_REV_5703 0x01
#define ASIC_REV_5704 0x02
#define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8)
#define CHIPREV_5700_AX 0x70
#define CHIPREV_5700_BX 0x71
...
...
@@ -165,6 +173,7 @@
#define PCISTATE_ROM_ENABLE 0x00000020
#define PCISTATE_ROM_RETRY_ENABLE 0x00000040
#define PCISTATE_FLAT_VIEW 0x00000100
#define PCISTATE_RETRY_SAME_DMA 0x00002000
#define TG3PCI_CLOCK_CTRL 0x00000074
#define CLOCK_CTRL_CORECLK_DISABLE 0x00000200
#define CLOCK_CTRL_RXCLK_DISABLE 0x00000400
...
...
@@ -843,6 +852,8 @@
#define RDMAC_MODE_FIFOURUN_ENAB 0x00000080
#define RDMAC_MODE_FIFOOREAD_ENAB 0x00000100
#define RDMAC_MODE_LNGREAD_ENAB 0x00000200
#define RDMAC_MODE_SPLIT_ENABLE 0x00000800
#define RDMAC_MODE_SPLIT_RESET 0x00001000
#define RDMAC_STATUS 0x00004804
#define RDMAC_STATUS_TGTABORT 0x00000004
#define RDMAC_STATUS_MSTABORT 0x00000008
...
...
@@ -1126,6 +1137,8 @@
#define GRC_MISC_CFG_BOARD_ID_5702FE 0x00004000
#define GRC_MISC_CFG_BOARD_ID_5703 0x00000000
#define GRC_MISC_CFG_BOARD_ID_5703S 0x00002000
#define GRC_MISC_CFG_BOARD_ID_5704 0x00000000
#define GRC_MISC_CFG_BOARD_ID_5704CIOBE 0x00004000
#define GRC_MISC_CFG_BOARD_ID_AC91002A1 0x00018000
#define GRC_LOCAL_CTRL 0x00006808
#define GRC_LCLCTRL_INT_ACTIVE 0x00000001
...
...
@@ -1248,14 +1261,19 @@
#define NIC_SRAM_DATA_SIG_MAGIC 0x4b657654
/* ascii for 'KevT' */
#define NIC_SRAM_DATA_CFG 0x00000b58
#define NIC_SRAM_DATA_CFG_PHY_TYPE_MASK 0x0000000c
#define NIC_SRAM_DATA_CFG_PHY_TYPE_UNKNOWN 0x00000000
#define NIC_SRAM_DATA_CFG_PHY_TYPE_COPPER 0x00000004
#define NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER 0x00000008
#define NIC_SRAM_DATA_CFG_LED_MODE_MASK 0x00000030
#define NIC_SRAM_DATA_CFG_LED_MODE_MASK 0x0000000c
#define NIC_SRAM_DATA_CFG_LED_MODE_UNKNOWN 0x00000000
#define NIC_SRAM_DATA_CFG_LED_TRIPLE_SPD 0x00000010
#define NIC_SRAM_DATA_CFG_LED_LINK_SPD 0x00000020
#define NIC_SRAM_DATA_CFG_LED_TRIPLE_SPD 0x00000004
#define NIC_SRAM_DATA_CFG_LED_OPEN_DRAIN 0x00000004
#define NIC_SRAM_DATA_CFG_LED_LINK_SPD 0x00000008
#define NIC_SRAM_DATA_CFG_LED_OUTPUT 0x00000008
#define NIC_SRAM_DATA_CFG_PHY_TYPE_MASK 0x00000030
#define NIC_SRAM_DATA_CFG_PHY_TYPE_UNKNOWN 0x00000000
#define NIC_SRAM_DATA_CFG_PHY_TYPE_COPPER 0x00000010
#define NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER 0x00000020
#define NIC_SRAM_DATA_CFG_WOL_ENABLE 0x00000040
#define NIC_SRAM_DATA_CFG_ASF_ENABLE 0x00000080
#define NIC_SRAM_DATA_CFG_EEPROM_WP 0x00000100
#define NIC_SRAM_DATA_PHY_ID 0x00000b74
#define NIC_SRAM_DATA_PHY_ID1_MASK 0xffff0000
...
...
@@ -1292,7 +1310,8 @@
#define NIC_SRAM_RX_BUFFER_DESC 0x00006000
/* 256 entries */
#define NIC_SRAM_RX_JUMBO_BUFFER_DESC 0x00007000
/* 256 entries */
#define NIC_SRAM_MBUF_POOL_BASE 0x00008000
#define NIC_SRAM_MBUF_POOL_SIZE 0x00018000
#define NIC_SRAM_MBUF_POOL_SIZE96 0x00018000
#define NIC_SRAM_MBUF_POOL_SIZE64 0x00018000
/* Currently this is fixed. */
#define PHY_ADDR 0x01
...
...
@@ -1410,6 +1429,7 @@ struct tg3_tx_buffer_desc {
u32
vlan_tag
;
#define TXD_VLAN_TAG_SHIFT 0
#define TXD_MSS_SHIFT 16
};
#define TXD_ADDR 0x00UL
/* 64-bit */
...
...
@@ -1660,6 +1680,12 @@ struct ring_info {
DECLARE_PCI_UNMAP_ADDR
(
mapping
)
};
struct
tx_ring_info
{
struct
sk_buff
*
skb
;
DECLARE_PCI_UNMAP_ADDR
(
mapping
)
u32
prev_vlan_tag
;
};
struct
tg3_config_info
{
u32
flags
;
};
...
...
@@ -1737,11 +1763,13 @@ struct tg3 {
#define TG3_FLAG_RX_CHECKSUMS 0x00000004
#define TG3_FLAG_USE_LINKCHG_REG 0x00000008
#define TG3_FLAG_USE_MI_INTERRUPT 0x00000010
#define TG3_FLAG_ENABLE_ASF 0x00000020
#define TG3_FLAG_POLL_SERDES 0x00000080
#define TG3_FLAG_
PHY_RESET_ON_INIT
0x00000100
#define TG3_FLAG_
MBOX_WRITE_REORDER
0x00000100
#define TG3_FLAG_PCIX_TARGET_HWBUG 0x00000200
#define TG3_FLAG_WOL_SPEED_100MB 0x00000400
#define TG3_FLAG_WOL_ENABLE 0x00001000
#define TG3_FLAG_WOL_ENABLE 0x00000800
#define TG3_FLAG_EEPROM_WRITE_PROT 0x00001000
#define TG3_FLAG_NVRAM 0x00002000
#define TG3_FLAG_NVRAM_BUFFERED 0x00004000
#define TG3_FLAG_RX_PAUSE 0x00008000
...
...
@@ -1759,14 +1787,20 @@ struct tg3 {
#define TG3_FLAG_PAUSE_TX 0x08000000
#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000
#define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000
#define TG3_FLAG_SPLIT_MODE 0x40000000
#define TG3_FLAG_INIT_COMPLETE 0x80000000
u32
msg_enable
;
u32
split_mode_max_reqs
;
#define SPLIT_MODE_5704_MAX_REQ 3
struct
timer_list
timer
;
u16
timer_counter
;
u16
timer_multiplier
;
u32
timer_offset
;
u16
asf_counter
;
u16
asf_multiplier
;
struct
tg3_link_config
link_config
;
struct
tg3_bufmgr_config
bufmgr_config
;
...
...
@@ -1807,6 +1841,7 @@ struct tg3 {
#define PHY_ID_BCM5411 0x60008070
#define PHY_ID_BCM5701 0x60008110
#define PHY_ID_BCM5703 0x60008160
#define PHY_ID_BCM5704 0x60008190
#define PHY_ID_BCM8002 0x60010140
#define PHY_ID_SERDES 0xfeedbee0
#define PHY_ID_INVALID 0xffffffff
...
...
@@ -1826,7 +1861,7 @@ struct tg3 {
#define KNOWN_PHY_ID(X) \
((X) == PHY_ID_BCM5400 || (X) == PHY_ID_BCM5401 || \
(X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \
(X) == PHY_ID_BCM5703 ||
\
(X) == PHY_ID_BCM5703 ||
(X) == PHY_ID_BCM5704 ||
\
(X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES)
unsigned
long
regs
;
...
...
@@ -1853,7 +1888,7 @@ struct tg3 {
/* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */
struct
tg3_tx_buffer_desc
*
tx_ring
;
struct
ring_info
*
tx_buffers
;
struct
tx_
ring_info
*
tx_buffers
;
dma_addr_t
tx_desc_mapping
;
struct
tg3_hw_status
*
hw_status
;
...
...
drivers/pci/pci.ids
View file @
d038b8c5
...
...
@@ -5053,6 +5053,7 @@
14e4 000b BCM5703 1000BaseTX
14e4 8009 BCM5703 1000BaseTX
14e4 800a BCM5703 1000BaseTX
1648 NetXtreme BCM5704 Gigabit Ethernet
164d NetXtreme BCM5702FE Gigabit Ethernet
16a6 NetXtreme BCM5702X Gigabit Ethernet
16a7 NetXtreme BCM5703X Gigabit Ethernet
...
...
include/linux/llc.h
View file @
d038b8c5
...
...
@@ -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/linux/pci_ids.h
View file @
d038b8c5
...
...
@@ -1561,6 +1561,7 @@
#define PCI_DEVICE_ID_TIGON3_5701 0x1645
#define PCI_DEVICE_ID_TIGON3_5702 0x1646
#define PCI_DEVICE_ID_TIGON3_5703 0x1647
#define PCI_DEVICE_ID_TIGON3_5704 0x1648
#define PCI_DEVICE_ID_TIGON3_5702FE 0x164d
#define PCI_DEVICE_ID_TIGON3_5702X 0x16a6
#define PCI_DEVICE_ID_TIGON3_5703X 0x16a7
...
...
include/net/llc_c_st.h
View file @
d038b8c5
...
...
@@ -33,15 +33,15 @@
/* Connection state table structure */
struct
llc_conn_state_trans
{
llc_conn_ev_t
ev
;
u8
next_state
;
llc_conn_ev_qfyr_t
*
ev_qualifiers
;
llc_conn_action_t
*
ev_actions
;
llc_conn_ev_t
ev
;
u8
next_state
;
llc_conn_ev_qfyr_t
*
ev_qualifiers
;
llc_conn_action_t
*
ev_actions
;
};
struct
llc_conn_state
{
u8
current_state
;
struct
llc_conn_state_trans
**
transitions
;
u8
current_state
;
struct
llc_conn_state_trans
**
transitions
;
};
extern
struct
llc_conn_state
llc_conn_state_table
[];
...
...
include/net/llc_conn.h
View file @
d038b8c5
...
...
@@ -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,8 +96,11 @@ 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
,
struct
llc_addr
*
laddr
);
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
);
#endif
/* LLC_CONN_H */
include/net/llc_if.h
View file @
d038b8c5
...
...
@@ -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 @
d038b8c5
...
...
@@ -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
,
struct
packet_type
*
pt
);
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 @
d038b8c5
...
...
@@ -61,8 +61,8 @@ 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
,
struct
sk_buff
*
skb
);
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
);
extern
struct
sk_buff
*
llc_alloc_frame
(
void
);
...
...
include/net/llc_pdu.h
View file @
d038b8c5
...
...
@@ -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
,
u8
rx_window
);
extern
int
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
,
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_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
void
llc_pdu_init_as_test_rsp
(
struct
sk_buff
*
skb
,
struct
sk_buff
*
ev_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
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 @
d038b8c5
...
...
@@ -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'
...
...
@@ -32,7 +31,6 @@ struct llc_sap {
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 +47,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/8021q/vlan.c
View file @
d038b8c5
...
...
@@ -626,7 +626,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
ret
=
unregister_vlan_dev
(
dev
,
VLAN_DEV_INFO
(
vlandev
)
->
vlan_id
);
unregister_netdev
(
vlandev
);
unregister_netdev
ice
(
vlandev
);
/* Group was destroyed? */
if
(
ret
==
1
)
...
...
net/core/dev.c
View file @
d038b8c5
...
...
@@ -694,10 +694,14 @@ int dev_open(struct net_device *dev)
* Call device private open method
*/
if
(
try_inc_mod_count
(
dev
->
owner
))
{
set_bit
(
__LINK_STATE_START
,
&
dev
->
state
);
if
(
dev
->
open
)
{
ret
=
dev
->
open
(
dev
);
if
(
ret
&&
dev
->
owner
)
__MOD_DEC_USE_COUNT
(
dev
->
owner
);
if
(
ret
)
{
clear_bit
(
__LINK_STATE_START
,
&
dev
->
state
);
if
(
dev
->
owner
)
__MOD_DEC_USE_COUNT
(
dev
->
owner
);
}
}
}
else
{
ret
=
-
ENODEV
;
...
...
@@ -713,8 +717,6 @@ int dev_open(struct net_device *dev)
*/
dev
->
flags
|=
IFF_UP
;
set_bit
(
__LINK_STATE_START
,
&
dev
->
state
);
/*
* Initialize multicasting status
*/
...
...
net/ipv4/ip_options.c
View file @
d038b8c5
...
...
@@ -266,7 +266,7 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb)
for
(
l
=
opt
->
optlen
;
l
>
0
;
)
{
switch
(
*
optptr
)
{
case
IPOPT_END
:
for
(
optptr
++
,
l
--
;
l
>
0
;
l
--
)
{
for
(
optptr
++
,
l
--
;
l
>
0
;
optptr
++
,
l
--
)
{
if
(
*
optptr
!=
IPOPT_END
)
{
*
optptr
=
IPOPT_END
;
opt
->
is_changed
=
1
;
...
...
net/ipv4/tcp_input.c
View file @
d038b8c5
...
...
@@ -3289,17 +3289,24 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
if
((
s32
)(
tp
->
rcv_tsval
-
tp
->
ts_recent
)
<
0
)
goto
slow_path
;
/* Predicted packet is in window by definition.
* seq == rcv_nxt and rcv_wup <= rcv_nxt.
* Hence, check seq<=rcv_wup reduces to:
/* DO NOT update ts_recent here, if checksum fails
* and timestamp was corrupted part, it will result
* in a hung connection since we will drop all
* future packets due to the PAWS test.
*/
if
(
tp
->
rcv_nxt
==
tp
->
rcv_wup
)
tcp_store_ts_recent
(
tp
);
}
if
(
len
<=
tcp_header_len
)
{
/* Bulk data transfer: sender */
if
(
len
==
tcp_header_len
)
{
/* Predicted packet is in window by definition.
* seq == rcv_nxt and rcv_wup <= rcv_nxt.
* Hence, check seq<=rcv_wup reduces to:
*/
if
(
tcp_header_len
==
(
sizeof
(
struct
tcphdr
)
+
TCPOLEN_TSTAMP_ALIGNED
)
&&
tp
->
rcv_nxt
==
tp
->
rcv_wup
)
tcp_store_ts_recent
(
tp
);
/* We know that such packets are checksummed
* on entry.
*/
...
...
@@ -3325,12 +3332,30 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
tp
->
rcv_nxt
=
TCP_SKB_CB
(
skb
)
->
end_seq
;
NET_INC_STATS_BH
(
TCPHPHitsToUser
);
eaten
=
1
;
/* Predicted packet is in window by definition.
* seq == rcv_nxt and rcv_wup <= rcv_nxt.
* Hence, check seq<=rcv_wup reduces to:
*/
if
(
tcp_header_len
==
(
sizeof
(
struct
tcphdr
)
+
TCPOLEN_TSTAMP_ALIGNED
)
&&
tp
->
rcv_nxt
==
tp
->
rcv_wup
)
tcp_store_ts_recent
(
tp
);
}
}
if
(
!
eaten
)
{
if
(
tcp_checksum_complete_user
(
sk
,
skb
))
goto
csum_error
;
/* Predicted packet is in window by definition.
* seq == rcv_nxt and rcv_wup <= rcv_nxt.
* Hence, check seq<=rcv_wup reduces to:
*/
if
(
tcp_header_len
==
(
sizeof
(
struct
tcphdr
)
+
TCPOLEN_TSTAMP_ALIGNED
)
&&
tp
->
rcv_nxt
==
tp
->
rcv_wup
)
tcp_store_ts_recent
(
tp
);
if
((
int
)
skb
->
truesize
>
sk
->
forward_alloc
)
goto
step5
;
...
...
net/llc/llc_actn.c
View file @
d038b8c5
...
...
@@ -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 @
d038b8c5
...
...
@@ -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,12 +1300,15 @@ int llc_conn_ac_upd_nr_received(struct sock *sk, struct sk_buff *skb)
int
llc_conn_ac_upd_p_flag
(
struct
sock
*
sk
,
struct
sk_buff
*
skb
)
{
struct
llc_pdu_sn
*
pdu
=
llc_pdu_sn_hdr
(
skb
);
u8
f_bit
;
if
(
!
LLC_PDU_IS_RSP
(
pdu
)
&&
!
llc_pdu_decode_pf_bit
(
skb
,
&
f_bit
)
&&
f_bit
)
{
llc_sk
(
sk
)
->
p_flag
=
0
;
llc_conn_ac_stop_p_timer
(
sk
,
skb
);
if
(
!
LLC_PDU_IS_RSP
(
pdu
))
{
u8
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
;
}
if
(
!
sk
->
lock
.
users
)
llc_conn_send_ev
(
sk
,
skb
);
else
{
llc_set_backlog_type
(
skb
,
LLC_EVENT
);
sk_add_backlog
(
sk
,
skb
);
}
else
{
if
(
!
sk
->
lock
.
users
)
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 @
d038b8c5
...
...
@@ -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 @
d038b8c5
...
...
@@ -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
;
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 */
/*
* 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
);
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 */
llc
->
sap
->
ind
(
ind_prim
);
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,8 +478,8 @@ 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
llc_addr
*
laddr
)
struct
sock
*
llc_
lookup_established
(
struct
llc_sap
*
sap
,
struct
llc_addr
*
daddr
,
struct
llc_addr
*
laddr
)
{
struct
sock
*
rc
=
NULL
;
struct
list_head
*
entry
;
...
...
@@ -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 @
d038b8c5
...
...
@@ -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.
* llc_build_and_send_ui_pkt - unitdata request interface for upper layers
* @sap: sap to use
* @skb: packet to send
* @addr: destination address
*
* 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.
* Upper layers calls this function when upper layer wants to send data
* using connection-less mode communication (UI pdu).
*
* Accept data frame from network layer to be sent using connection-
* less mode communication; timeout/retries handled by network layer;
* package primitive as an event and send to SAP event handler
*/
static
int
llc_sap_req
(
struct
llc_prim_if_block
*
prim
)
void
llc_build_and_send_ui_pkt
(
struct
llc_sap
*
sap
,
struct
sk_buff
*
skb
,
struct
sockaddr_llc
*
addr
)
{
int
rc
=
1
;
union
llc_u_prim_data
prim_data
;
struct
llc_prim_if_block
prim
;
struct
llc_sap_state_ev
*
ev
=
llc_sap_ev
(
skb
);
if
(
prim
->
prim
>
8
||
prim
->
prim
==
6
)
{
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
;
}
skb
->
protocol
=
llc_proto_type
(
addr
->
sllc_arphrd
);
/**
* llc_unitdata_req_handler - unitdata request interface for upper layers
* @prim: pointer to structure that contains service parameters
*
* 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-
* 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
);
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
->
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
=
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
=
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
* component state machine.
Success or failure of 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
(
daddr
.
mac
));
daddr
.
lsap
=
prim
->
data
->
conn
.
daddr
.
lsap
;
sk
=
llc_find_sock
(
sap
,
&
daddr
,
&
laddr
);
if
(
sk
)
{
llc_confirm_impossible
(
prim
);
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
;
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
(
laddr
.
mac
));
existing
=
llc_lookup_established
(
llc
->
sap
,
&
daddr
,
&
laddr
);
if
(
existing
)
{
if
(
existing
->
state
==
TCP_ESTABLISHED
)
{
sk
=
existing
;
goto
out_put
;
}
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_send_ev
(
sk
,
skb
);
}
if
(
rc
)
{
llc_sap_unassign_sock
(
sap
,
sk
);
llc_sock_free
(
sk
);
llc_confirm_impossible
(
prim
);
ev
->
data
.
prim
.
data
=
NULL
;
rc
=
llc_conn_state_process
(
sk
,
skb
);
}
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
;
ev
=
llc_conn_ev
(
skb
);
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_s
end_ev
(
sk
,
skb
);
rc
=
llc_conn_s
tate_process
(
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
);
}
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 @
d038b8c5
...
...
@@ -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_sock_alloc
();
if
(
!
sk
)
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
*/
struct
llc_opt
*
llc
;
struct
sock
*
parent
;
parent
=
llc_lookup_listener
(
sap
,
&
daddr
);
if
(
!
parent
)
{
dprintk
(
"llc_lookup_listener failed!
\n
"
);
goto
drop
;
}
sk
=
llc_sk_alloc
(
parent
->
family
,
GFP_ATOMIC
);
if
(
!
sk
)
{
sock_put
(
parent
);
goto
drop
;
memcpy
(
&
llc_sk
(
sk
)
->
daddr
,
&
saddr
,
sizeof
(
saddr
));
}
llc
=
llc_sk
(
sk
);
memcpy
(
&
llc
->
laddr
,
&
daddr
,
sizeof
(
llc
->
laddr
));
memcpy
(
&
llc
->
daddr
,
&
saddr
,
sizeof
(
llc
->
daddr
));
llc_sap_assign_sock
(
sap
,
sk
);
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
;
struct
llc_
station
*
station
=
llc_station_get
(
);
struct
llc_station_state_ev
*
ev
=
llc_station_ev
(
skb
)
;
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_state_process
(
station
,
skb
);
}
ev
->
type
=
LLC_STATION_EV_TYPE_PDU
;
ev
->
data
.
pdu
.
reason
=
0
;
llc_station_send_ev
(
station
,
skb
);
}
else
if
(
type
==
LLC_TYPE_1
)
{
struct
llc_sap_state_ev
*
ev
=
llc_sap_ev
(
skb
);
ev
->
type
=
LLC_SAP_EV_TYPE_PDU
;
ev
->
data
.
pdu
.
reason
=
0
;
llc_sap_send_ev
(
sap
,
skb
);
}
else
if
(
type
==
LLC_TYPE_2
)
{
struct
llc_conn_state_ev
*
ev
=
llc_conn_ev
(
skb
);
struct
llc_opt
*
llc
=
llc_sk
(
sk
);
/**
* 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
;
if
(
!
llc
->
dev
)
llc
->
dev
=
skb
->
dev
;
ev
->
type
=
LLC_CONN_EV_TYPE_PDU
;
ev
->
data
.
pdu
.
reason
=
0
;
return
llc_conn_state_process
(
sk
,
skb
);
}
ev
->
type
=
LLC_CONN_EV_TYPE_PDU
;
ev
->
data
.
pdu
.
reason
=
0
;
rc
=
llc_conn_send_ev
(
sk
,
skb
);
}
else
rc
=
-
EINVAL
;
return
rc
;
/**
* 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 @
d038b8c5
...
...
@@ -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
)
sock_put
(
sk
);
#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 @
d038b8c5
...
...
@@ -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,8 +192,8 @@ int llc_pdu_init_as_ui_cmd(struct sk_buff *skb)
* This function sets third,fourth,fifth and sixth bytes of LLC header as
* a XID PDU.
*/
int
llc_pdu_init_as_xid_cmd
(
struct
sk_buff
*
skb
,
u8
svcs_supported
,
u8
rx_window
)
void
llc_pdu_init_as_xid_cmd
(
struct
sk_buff
*
skb
,
u8
svcs_supported
,
u8
rx_window
)
{
struct
llc_xid_info
*
xid_info
;
struct
llc_pdu_un
*
pdu
=
llc_pdu_un_hdr
(
skb
);
...
...
@@ -220,7 +206,6 @@ int llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported,
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,53 +316,50 @@ int llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr)
pdu
->
ctrl_2
=
p_bit
&
LLC_S_PF_BIT_MASK
;
pdu
->
ctrl_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
,
u8
rx_window
)
void
llc_pdu_init_as_xid_rsp
(
struct
sk_buff
*
skb
,
u8
svcs_supported
,
u8
rx_window
)
{
struct
llc_xid_info
*
xid_info
;
struct
llc_pdu_un
*
pdu
=
llc_pdu_un_hdr
(
skb
);
...
...
@@ -396,17 +373,16 @@ int llc_pdu_init_as_xid_rsp(struct sk_buff *skb, u8 svcs_supported,
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,8 +410,8 @@ int llc_pdu_init_as_test_rsp(struct sk_buff *skb, struct sk_buff *ev_skb)
*
* Builds a pdu frame as a FRMR response.
*/
int
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
)
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
;
u8
prev_pf
=
0
;
...
...
@@ -460,18 +435,17 @@ int llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, struct llc_pdu_sn *prev_pdu,
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 @
d038b8c5
...
...
@@ -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 @
d038b8c5
...
...
@@ -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 @
d038b8c5
...
...
@@ -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.
* 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
,
laddr
->
mac
))
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
;
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
));
rc
=
0
;
sock_init_data
(
sock
,
sk
);
llc_ui_sk
(
sk
)
=
llc_ui
;
sock
->
ops
=
&
llc_ui_ops
;
out:
if
(
sock
->
type
==
SOCK_DGRAM
||
sock
->
type
==
SOCK_STREAM
)
{
rc
=
-
ENOMEM
;
sk
=
llc_sk_alloc
(
PF_LLC
,
GFP_KERNEL
);
if
(
sk
)
{
rc
=
0
;
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
);
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
);
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
->
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
))
goto
out
;
}
}
while
(
!
skb
);
rc
=
-
EINVAL
;
if
(
!
skb
->
sk
)
goto
frees
;
/* attach connection to a new socket. */
rc
=
llc_ui_create
(
newsock
,
sk
->
protocol
);
rc
=
llc_ui_wait_for_data
(
sk
,
sk
->
rcvtimeo
);
if
(
rc
)
goto
out
;
dprintk
(
"%s: got a new connection on %02X
\n
"
,
__FUNCTION__
,
llc_sk
(
sk
)
->
addr
.
sllc_ssap
);
skb
=
skb_dequeue
(
&
sk
->
receive_queue
);
rc
=
-
EINVAL
;
if
(
!
skb
->
sk
)
goto
frees
;
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