summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.transmeta.com>2002-09-13 04:10:14 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2002-09-13 04:10:14 -0700
commitd038b8c52e647b144fea7a032cae78677d0c819e (patch)
treef781b5f3146d7dd93b1dee81c116efa6e7892296
parentd1a75a97b0d3b9bc4e6a95f4e7854e7a7a986976 (diff)
parent1a2c129e137343fed08fd9c61b353cabc6b72aaa (diff)
Merge master.kernel.org:/home/davem/BK/net-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
-rw-r--r--drivers/net/tg3.c1096
-rw-r--r--drivers/net/tg3.h59
-rw-r--r--drivers/pci/pci.ids1
-rw-r--r--include/linux/llc.h11
-rw-r--r--include/linux/pci_ids.h1
-rw-r--r--include/net/llc_c_st.h12
-rw-r--r--include/net/llc_conn.h73
-rw-r--r--include/net/llc_if.h68
-rw-r--r--include/net/llc_mac.h41
-rw-r--r--include/net/llc_main.h4
-rw-r--r--include/net/llc_pdu.h56
-rw-r--r--include/net/llc_sap.h4
-rw-r--r--net/8021q/vlan.c2
-rw-r--r--net/core/dev.c10
-rw-r--r--net/ipv4/ip_options.c2
-rw-r--r--net/ipv4/tcp_input.c35
-rw-r--r--net/llc/llc_actn.c4
-rw-r--r--net/llc/llc_c_ac.c153
-rw-r--r--net/llc/llc_c_ev.c20
-rw-r--r--net/llc/llc_conn.c216
-rw-r--r--net/llc/llc_if.c441
-rw-r--r--net/llc/llc_mac.c169
-rw-r--r--net/llc/llc_main.c85
-rw-r--r--net/llc/llc_pdu.c130
-rw-r--r--net/llc/llc_s_ac.c23
-rw-r--r--net/llc/llc_sap.c33
-rw-r--r--net/llc/llc_sock.c963
27 files changed, 2054 insertions, 1658 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index bf08bba649eb..122b5aa10204 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -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(20);
+ tr32(MAC_STATUS);
+ udelay(40);
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(20);
+ tr32(MAC_STATUS);
+ udelay(40);
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 @@ next_pkt_nopost:
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
- u16 vlan_tag = 0;
-#endif
+ int is_end = (mss_and_is_end & 0x1);
+ u32 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);
@@ -2943,11 +3133,33 @@ static void tg3_chip_reset(struct tg3 *tp)
}
/* 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 tg3FwText[(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 tg3FwRodata[(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 tg3FwData[(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;
diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h
index 02b7b77d5f4c..754f638f890a 100644
--- a/drivers/net/tg3.h
+++ b/drivers/net/tg3.h
@@ -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;
diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids
index 186c8fdd99ad..3290c4213660 100644
--- a/drivers/pci/pci.ids
+++ b/drivers/pci/pci.ids
@@ -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
diff --git a/include/linux/llc.h b/include/linux/llc.h
index 824a149e9e6b..77ac5d9df544 100644
--- a/include/linux/llc.h
+++ b/include/linux/llc.h
@@ -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
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 5eea9545b69a..9a1ad256e2cc 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -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
diff --git a/include/net/llc_c_st.h b/include/net/llc_c_st.h
index f0b40ed22754..0e79cfba4b3b 100644
--- a/include/net/llc_c_st.h
+++ b/include/net/llc_c_st.h
@@ -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[];
diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h
index db42c7f6fc78..5846a5b91841 100644
--- a/include/net/llc_conn.h
+++ b/include/net/llc_conn.h
@@ -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_sock_reset(struct sock *sk);
-extern int llc_sock_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_send_ev(struct sock *sk, struct sk_buff *skb);
+extern int llc_conn_state_process(struct sock *sk, struct sk_buff *skb);
extern void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb);
extern void llc_conn_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 */
diff --git a/include/net/llc_if.h b/include/net/llc_if.h
index cc2348004161..e17373a17c00 100644
--- a/include/net/llc_if.h
+++ b/include/net/llc_if.h
@@ -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 */
diff --git a/include/net/llc_mac.h b/include/net/llc_mac.h
index 9f2fb80ba98e..3ab584987448 100644
--- a/include/net/llc_mac.h
+++ b/include/net/llc_mac.h
@@ -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 */
diff --git a/include/net/llc_main.h b/include/net/llc_main.h
index e3aa4d2c7632..31810831fceb 100644
--- a/include/net/llc_main.h
+++ b/include/net/llc_main.h
@@ -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_send_ev(struct llc_station *station,
- struct sk_buff *skb);
+extern void llc_station_state_process(struct llc_station *station,
+ struct sk_buff *skb);
extern void llc_station_send_pdu(struct llc_station *station,
struct sk_buff *skb);
extern struct sk_buff *llc_alloc_frame(void);
diff --git a/include/net/llc_pdu.h b/include/net/llc_pdu.h
index 6236c0cab669..02145e59174c 100644
--- a/include/net/llc_pdu.h
+++ b/include/net/llc_pdu.h
@@ -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 */
diff --git a/include/net/llc_sap.h b/include/net/llc_sap.h
index 3fd694a166e6..3132bebd1422 100644
--- a/include/net/llc_sap.h
+++ b/include/net/llc_sap.h
@@ -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_send_ev(struct llc_sap *sap, struct sk_buff *skb);
+extern void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb);
extern void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb);
extern void llc_sap_send_pdu(struct llc_sap *sap, struct sk_buff *skb);
#endif /* LLC_SAP_H */
diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c
index 7f15168db0c3..6f21903b0932 100644
--- a/net/8021q/vlan.c
+++ b/net/8021q/vlan.c
@@ -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_netdevice(vlandev);
/* Group was destroyed? */
if (ret == 1)
diff --git a/net/core/dev.c b/net/core/dev.c
index e67776f3a9ba..be5f1c87d480 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -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
*/
diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c
index 8faded2b254f..915da9809100 100644
--- a/net/ipv4/ip_options.c
+++ b/net/ipv4/ip_options.c
@@ -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;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index 7072ab51cf27..8c1d316db7b5 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -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;
diff --git a/net/llc/llc_actn.c b/net/llc/llc_actn.c
index 4b63a130b0c9..dadb22054749 100644
--- a/net/llc/llc_actn.c
+++ b/net/llc/llc_actn.c
@@ -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_send_ev(station, skb);
+ llc_station_state_process(station, skb);
}
}
diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c
index 96e61732c317..88a3c2f7e6be 100644
--- a/net/llc/llc_c_ac.c
+++ b/net/llc/llc_c_ac.c
@@ -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_sock_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 otherwise.
+ * Queued events will process by llc_backlog_rcv function after sending
+ * data frame.
*/
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);
}
diff --git a/net/llc/llc_c_ev.c b/net/llc/llc_c_ev.c
index e300584ac8f8..9b455714143a 100644
--- a/net/llc/llc_c_ev.c
+++ b/net/llc/llc_c_ev.c
@@ -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;
}
diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c
index 98072a6c552d..377887a246e4 100644
--- a/net/llc/llc_conn.c
+++ b/net/llc/llc_conn.c
@@ -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_send_event - sends event to connection state machine
+ * llc_conn_state_process - sends event to connection state machine
* @sk: connection
* @skb: occurred event
*
- * Sends an event to connection state machine. after processing event
+ * Sends an event to connection state machine. After processing event
* (executing it's actions and changing state), upper layer will be
* 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_send_ev(struct sock *sk, struct sk_buff *skb)
+int llc_conn_state_process(struct sock *sk, struct sk_buff *skb)
{
/* sending event to state machine */
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_send_ev.
+ * function will be done in llc_conn_state_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;
}
@@ -433,6 +506,39 @@ out:
}
/**
+ * 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 @@ out:
*/
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;
}
/**
diff --git a/net/llc/llc_if.c b/net/llc/llc_if.c
index a53cc174adf0..393173d91156 100644
--- a/net/llc/llc_if.c
+++ b/net/llc/llc_if.c
@@ -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. each one who wants to get a SAP
+ * Interface function to upper layer. Each one who wants to get a SAP
* (for example NetBEUI) should call this function. Returns the opened
* 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 @@ err:
* llc_sap_close - close interface for upper layers.
* @sap: SAP to be closed.
*
- * Close interface function to upper layer. each one who wants to
+ * Close interface function to upper layer. Each 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. during sending data, connection
+ * connection oriented communication mode. During 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_send_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_state_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. this function packages a proper event and sends it connection
- * component state machine. Success or failure of connection
+ * machine. This 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. this function packages a proper event
+ * connection with a remote machine. This function packages a proper event
* and sends it to connection component state machine. Returns 0 for
* 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_send_ev(sk, skb);
+ ev->data.prim.data = NULL;
+ rc = llc_conn_state_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. this function packages a proper event and sends
+ * with a remote machine. This function packages a proper event and sends
* it to connection component state machine. Returns 0 for success, 1
* 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 sock *sk = prim->data->res.sk;
+ struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC);
- lock_sock(sk);
- skb = alloc_skb(1, GFP_ATOMIC);
if (skb) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb);
@@ -437,87 +345,10 @@ static int llc_rst_req_handler(struct llc_prim_if_block *prim)
ev->data.prim.prim = LLC_RESET_PRIM;
ev->data.prim.type = LLC_PRIM_TYPE_REQ;
ev->data.prim.data = prim;
- rc = llc_conn_send_ev(sk, skb);
+ rc = llc_conn_state_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);
diff --git a/net/llc/llc_mac.c b/net/llc/llc_mac.c
index d71eae9c79a0..381ea3f58a78 100644
--- a/net/llc/llc_mac.c
+++ b/net/llc/llc_mac.c
@@ -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 @@ out:
}
/**
- * 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);
}
/**
diff --git a/net/llc/llc_main.c b/net/llc/llc_main.c
index 0aee057d1909..cdb0b6e6020b 100644
--- a/net/llc/llc_main.c
+++ b/net/llc/llc_main.c
@@ -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_send_ev(sk, skb);
+ rc = llc_conn_state_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_sock_init - Initialize a socket with default llc values.
+ * llc_sk_init - Initializes a socket with default llc values.
* @sk: socket to intiailize.
+ *
+ * Initializes a socket with default llc values.
*/
-int llc_sock_init(struct sock* sk)
+int llc_sk_init(struct sock* sk)
{
struct llc_opt *llc = kmalloc(sizeof(*llc), GFP_ATOMIC);
int rc = -ENOMEM;
@@ -198,61 +205,83 @@ out:
}
/**
- * __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_sock_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_sock_free - Frees a LLC socket
+ * llc_sk_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;
- /* stop all (possibly) running timers */
+ /* Stop 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_sock_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_sock_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_send_ev: queue event and try to process queue.
+ * llc_station_state_process: queue event and try to process queue.
* @station: Address of the station
* @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_send_ev(struct llc_station *station, struct sk_buff *skb)
+void llc_station_state_process(struct llc_station *station, struct sk_buff *skb)
{
spin_lock_bh(&station->ev_q.lock);
skb_queue_tail(&station->ev_q.list, skb);
@@ -557,13 +580,13 @@ unlock:
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();
diff --git a/net/llc/llc_pdu.c b/net/llc/llc_pdu.c
index f62dec772a0a..069ec96c9312 100644
--- a/net/llc/llc_pdu.c
+++ b/net/llc/llc_pdu.c
@@ -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 - extracts 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. right bit of SSAP is
+ * This function extracts source SAP of input frame. Right 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;
}
/**
diff --git a/net/llc/llc_s_ac.c b/net/llc/llc_s_ac.c
index f2be18568aec..e3f8ff640a82 100644
--- a/net/llc/llc_s_ac.c
+++ b/net/llc/llc_s_ac.c
@@ -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);
diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c
index 9986782135b1..15ad186dcdd9 100644
--- a/net/llc/llc_sap.c
+++ b/net/llc/llc_sap.c
@@ -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_send_ev - sends event to SAP state machine
+ * llc_sap_state_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_send_ev(struct llc_sap *sap, struct sk_buff *skb)
+void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb)
{
struct llc_sap_state_ev *ev = llc_sap_ev(skb);
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");
}
/**
@@ -143,19 +143,6 @@ void llc_sap_send_pdu(struct llc_sap *sap, struct sk_buff *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
* @skb: happened event
@@ -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];
diff --git a/net/llc/llc_sock.c b/net/llc/llc_sock.c
index 4acbbd335228..74a6a6b26e57 100644
--- a/net/llc/llc_sock.c
+++ b/net/llc/llc_sock.c
@@ -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,64 +72,21 @@ 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.
* @addr: Complete sockaddr_llc structure received from the user.
@@ -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;
@@ -141,138 +108,33 @@ static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr)
}
/**
- * 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 sk_buff *skb, struct sockaddr_llc *addr)
+static int llc_ui_send_data(struct sock* sk, struct sk_buff *skb,
+ struct sockaddr_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 @@ decmod:
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 @@ out:
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 @@ out:
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_SEQPACKET && sk->type != SOCK_STREAM)
+ 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 = -EOPNOTSUPP, size = 0;
+ int rc = -EINVAL, size = 0;
+ dprintk("%s: sending from %02X to %02X\n", __FUNCTION__, llc->laddr.lsap, llc->daddr.lsap);
lock_sock(sk);
- 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);
@@ -1471,35 +1275,6 @@ 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,92 +1292,24 @@ 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, "SocketID SKt Mc local_mac_sap\t "
- "remote_mac_sap\t tx_queue rx_queue st uid "
- "link_no\n");
+ int len = sprintf(buffer, "SKt 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 %02d %-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)
{