Commit d038b8c5 authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/home/davem/BK/net-2.5

into home.transmeta.com:/home/torvalds/v2.5/linux
parents d1a75a97 1a2c129e
......@@ -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 @@ static int tg3_rx(struct tg3 *tp, int budget)
tp->rx_rcb_ptr = rx_rcb_ptr;
tw32_mailbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW,
(rx_rcb_ptr % TG3_RX_RCB_RING_SIZE));
if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
tr32(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW);
/* Refill RX ring(s). */
if (work_mask & RXD_OPAQUE_RING_STD) {
sw_idx = tp->rx_std_ptr % TG3_RX_RING_SIZE;
tw32_mailbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW,
sw_idx);
if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
tr32(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW);
}
if (work_mask & RXD_OPAQUE_RING_JUMBO) {
sw_idx = tp->rx_jumbo_ptr % TG3_RX_JUMBO_RING_SIZE;
tw32_mailbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW,
sw_idx);
if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
tr32(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW);
}
#if TG3_MINI_RING_WORKS
if (work_mask & RXD_OPAQUE_RING_MINI) {
sw_idx = tp->rx_mini_ptr % TG3_RX_MINI_RING_SIZE;
tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW,
sw_idx);
if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER)
tr32(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW);
}
#endif
......@@ -1974,6 +2095,9 @@ static __inline__ void tg3_interrupt_main_work(struct net_device *dev, struct tg
return;
if (netif_rx_schedule_prep(dev)) {
/* NOTE: This write is posted by the readback of
* the mailbox register done by our caller.
*/
tw32(TG3PCI_MISC_HOST_CTRL,
(tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
__netif_rx_schedule(dev);
......@@ -1988,8 +2112,9 @@ static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
struct net_device *dev = dev_id;
struct tg3 *tp = dev->priv;
struct tg3_hw_status *sblk = tp->hw_status;
unsigned long flags;
spin_lock(&tp->lock);
spin_lock_irqsave(&tp->lock, flags);
if (sblk->status & SD_STATUS_UPDATED) {
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
......@@ -2003,7 +2128,7 @@ static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
}
spin_unlock(&tp->lock);
spin_unlock_irqrestore(&tp->lock, flags);
}
static void tg3_init_rings(struct tg3 *);
......@@ -2055,11 +2180,11 @@ static void tg3_set_txd_addr(struct tg3 *tp, int entry, dma_addr_t mapping)
}
#endif
static void tg3_set_txd(struct tg3 *, int, dma_addr_t, int, u32, int);
static void tg3_set_txd(struct tg3 *, int, dma_addr_t, int, u32, u32);
static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
u32 guilty_entry, int guilty_len,
u32 last_plus_one, u32 *start)
u32 last_plus_one, u32 *start, u32 mss)
{
dma_addr_t new_addr;
u32 entry = *start;
......@@ -2112,7 +2237,7 @@ static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
PCI_DMA_TODEVICE);
tg3_set_txd(tp, entry, new_addr, new_skb->len,
(skb->ip_summed == CHECKSUM_HW) ?
TXD_FLAG_TCPUDP_CSUM : 0, 1);
TXD_FLAG_TCPUDP_CSUM : 0, 1 | (mss << 1));
*start = NEXT_TX(entry);
/* Now clean up the sw ring entries. */
......@@ -2144,30 +2269,28 @@ static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb,
static void tg3_set_txd(struct tg3 *tp, int entry,
dma_addr_t mapping, int len, u32 flags,
int is_end)
u32 mss_and_is_end)
{
#if TG3_VLAN_TAG_USED
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);
......@@ -2942,12 +3132,34 @@ static void tg3_chip_reset(struct tg3 *tp)
tw32(TG3PCI_MISC_HOST_CTRL, tp->misc_host_ctrl);
}
/* tp->lock is held. */
static void tg3_stop_fw(struct tg3 *tp)
{
if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
u32 val;
int i;
tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_PAUSE_FW);
val = tr32(GRC_RX_CPU_EVENT);
val |= (1 << 14);
tw32(GRC_RX_CPU_EVENT, val);
/* Wait for RX cpu to ACK the event. */
for (i = 0; i < 100; i++) {
if (!(tr32(GRC_RX_CPU_EVENT) & (1 << 14)))
break;
udelay(1);
}
}
}
/* tp->lock is held. */
static int tg3_halt(struct tg3 *tp)
{
u32 val;
int i;
tg3_stop_fw(tp);
tg3_abort_hw(tp);
tg3_chip_reset(tp);
tg3_write_mem(tp,
......@@ -2967,6 +3179,17 @@ static int tg3_halt(struct tg3 *tp)
return -ENODEV;
}
if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) {
if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
DRV_STATE_WOL);
else
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
DRV_STATE_UNLOAD);
} else
tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX,
DRV_STATE_SUSPEND);
return 0;
}
......@@ -2985,7 +3208,7 @@ static int tg3_halt(struct tg3 *tp)
#define TG3_FW_BSS_ADDR 0x08000a70
#define TG3_FW_BSS_LEN 0x10
static u32 t3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = {
static u32 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;
......
......@@ -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;
......
......@@ -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
......
......@@ -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
......
......@@ -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
......
......@@ -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[];
......
......@@ -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 */
......@@ -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 */
......@@ -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 */
......@@ -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);
......
......@@ -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 */
......@@ -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 */
......@@ -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)
......
......@@ -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
*/
......
......@@ -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;
......
......@@ -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;
......
......@@ -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);
}
}
......@@ -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);
}
......@@ -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;
}
......
......@@ -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;
}
......@@ -432,6 +505,39 @@ struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr,
return rc;
}
/**
* llc_lookup_listener - Finds listener for local MAC + SAP
* @sap: SAP
* @laddr: address of local LLC (MAC + SAP)
*
* Search connection list of the SAP and finds connection listening on
* local mac, and local sap. Returns pointer for parent socket found,
* %NULL otherwise.
*/
struct sock *llc_lookup_listener(struct llc_sap *sap, struct llc_addr *laddr)
{
struct sock *rc = NULL;
struct list_head *entry;
spin_lock_bh(&sap->sk_list.lock);
if (list_empty(&sap->sk_list.list))
goto out;
list_for_each(entry, &sap->sk_list.list) {
struct llc_opt *llc = list_entry(entry, struct llc_opt, node);
if (llc->sk->type != SOCK_STREAM || llc->sk->state != TCP_LISTEN ||
llc->laddr.lsap != laddr->lsap ||
!llc_mac_match(llc->laddr.mac, laddr->mac))
continue;
rc = llc->sk;
}
if (rc)
sock_hold(rc);
out:
spin_unlock_bh(&sap->sk_list.lock);
return rc;
}
/**
* llc_data_accept_state - designates if in this state data can be sent.
* @state: state of connection.
......@@ -440,10 +546,8 @@ struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr,
*/
u8 llc_data_accept_state(u8 state)
{
if (state != LLC_CONN_STATE_NORMAL && state != LLC_CONN_STATE_BUSY &&
state != LLC_CONN_STATE_REJ)
return 1; /* data_conn_refuse */
return 0;
return state != LLC_CONN_STATE_NORMAL && state != LLC_CONN_STATE_BUSY &&
state != LLC_CONN_STATE_REJ;
}
/**
......
......@@ -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 @@ struct llc_sap *llc_sap_open(llc_prim_call_t nw_indicate,
* llc_sap_close - close interface for upper layers.
* @sap: SAP to be closed.
*
* Close interface function to upper layer. 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);
......@@ -27,14 +27,17 @@
#include <net/llc_s_ev.h>
#include <linux/trdevice.h>
#if 1
#if 0
#define dprintk(args...) printk(KERN_DEBUG args)
#else
#define dprintk(args...)
#endif
/* function prototypes */
u8 llc_mac_null_var[IFHWADDRLEN];
static void fix_up_incoming_skb(struct sk_buff *skb);
static void llc_station_rcv(struct sk_buff *skb);
static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb);
/**
* mac_send_pdu - Sends PDU to specific device.
......@@ -52,7 +55,7 @@ int mac_send_pdu(struct sk_buff *skb)
int pri = GFP_ATOMIC, rc = -1;
if (!skb->dev) {
dprintk(KERN_ERR "%s: skb->dev == NULL!", __FUNCTION__);
dprintk("%s: skb->dev == NULL!", __FUNCTION__);
goto out;
}
if (skb->sk)
......@@ -67,29 +70,30 @@ int mac_send_pdu(struct sk_buff *skb)
}
/**
* mac_indicate - 802.2 entry point from net lower layers
* llc_rcv - 802.2 entry point from net lower layers
* @skb: received pdu
* @dev: device that receive pdu
* @pt: packet type
*
* When the system receives a 802.2 frame this function is called. It
* checks SAP and connection of received pdu and passes frame to
* llc_pdu_router for sending to proper state machine. If frame is
* related to a busy connection (a connection is sending data now),
* function queues this frame in connection's backlog.
* llc_{station,sap,conn}_rcv for sending to proper state machine. If
* the frame is related to a busy connection (a connection is sending
* data now), it queues this frame in the connection's backlog.
*/
int mac_indicate(struct sk_buff *skb, struct net_device *dev,
int llc_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt)
{
struct llc_sap *sap;
struct llc_pdu_sn *pdu;
u8 dest;
/* When the interface is in promisc. mode, drop all the crap that it
/*
* When the interface is in promisc. mode, drop all the crap that it
* receives, do not try to analyse it.
*/
if (skb->pkt_type == PACKET_OTHERHOST) {
dprintk(KERN_INFO "%s: PACKET_OTHERHOST\n", __FUNCTION__);
dprintk("%s: PACKET_OTHERHOST\n", __FUNCTION__);
goto drop;
}
skb = skb_share_check(skb, GFP_ATOMIC);
......@@ -98,17 +102,19 @@ int mac_indicate(struct sk_buff *skb, struct net_device *dev,
fix_up_incoming_skb(skb);
pdu = llc_pdu_sn_hdr(skb);
if (!pdu->dsap) { /* NULL DSAP, refer to station */
if (llc_pdu_router(NULL, NULL, skb, 0))
goto drop;
dprintk("%s: calling llc_station_rcv!\n", __FUNCTION__);
llc_station_rcv(skb);
goto out;
}
sap = llc_sap_find(pdu->dsap);
if (!sap) /* unknown SAP */
if (!sap) {/* unknown SAP */
dprintk("%s: llc_sap_find(%02X) failed!\n", __FUNCTION__, pdu->dsap);
goto drop;
}
llc_decode_pdu_type(skb, &dest);
if (dest == LLC_DEST_SAP) { /* type 1 services */
if (llc_pdu_router(sap, NULL, skb, LLC_TYPE_1))
goto drop;
dprintk("%s: calling llc_sap_rcv!\n", __FUNCTION__);
llc_sap_rcv(sap, skb);
} else if (dest == LLC_DEST_CONN) {
struct llc_addr saddr, daddr;
struct sock *sk;
......@@ -119,34 +125,42 @@ int mac_indicate(struct sk_buff *skb, struct net_device *dev,
llc_pdu_decode_da(skb, daddr.mac);
llc_pdu_decode_dsap(skb, &daddr.lsap);
sk = llc_find_sock(sap, &saddr, &daddr);
if (!sk) { /* didn't find an active connection; allocate a
* connection to use; associate it with this SAP
*/
sk = llc_sock_alloc();
if (!sk)
sk = llc_lookup_established(sap, &saddr, &daddr);
if (!sk) {
/*
* Didn't find an active connection; verify if there
* is a listening socket for this llc addr
*/
struct llc_opt *llc;
struct sock *parent;
parent = llc_lookup_listener(sap, &daddr);
if (!parent) {
dprintk("llc_lookup_listener failed!\n");
goto drop;
}
sk = llc_sk_alloc(parent->family, GFP_ATOMIC);
if (!sk) {
sock_put(parent);
goto drop;
memcpy(&llc_sk(sk)->daddr, &saddr, sizeof(saddr));
}
llc = llc_sk(sk);
memcpy(&llc->laddr, &daddr, sizeof(llc->laddr));
memcpy(&llc->daddr, &saddr, sizeof(llc->daddr));
llc_sap_assign_sock(sap, sk);
sock_hold(sk);
}
sock_put(parent);
skb->sk = parent;
} else
skb->sk = sk;
bh_lock_sock(sk);
if (!sk->lock.users) {
/* FIXME: Check this on SMP as it is now calling
* llc_pdu_router _with_ the lock held.
* Old comment:
* With the current code one can't call
* llc_pdu_router with the socket lock held, cause
* it'll route the pdu to the upper layers and it can
* reenter llc and in llc_req_prim will try to grab
* the same lock, maybe we should use spin_trylock_bh
* in the llc_req_prim (llc_data_req_handler, etc) and
* add the request to the backlog, well see...
*/
rc = llc_pdu_router(llc_sk(sk)->sap, sk, skb,
LLC_TYPE_2);
/* rc = */ llc_conn_rcv(sk, skb);
rc = 0;
} else {
dprintk(KERN_INFO "%s: add to backlog\n", __FUNCTION__);
dprintk("%s: adding to backlog...\n", __FUNCTION__);
llc_set_backlog_type(skb, LLC_PACKET);
sk_add_backlog(sk, skb);
rc = 0;
......@@ -191,53 +205,56 @@ static void fix_up_incoming_skb(struct sk_buff *skb)
}
}
/**
* llc_pdu_router - routes received pdus to the upper layers
* @sap: current sap component structure.
* @sk: current connection structure.
* @frame: received frame.
* @type: type of received frame, that is LLC_TYPE_1 or LLC_TYPE_2
/*
* llc_station_rcv - send received pdu to the station state machine
* @skb: received frame.
*
* Queues received PDUs from LLC_MAC PDU receive queue until queue is
* empty; examines LLC header to determine the destination of PDU, if DSAP
* is NULL then data unit destined for station else frame destined for SAP
* or connection; finds a matching open SAP, if one, forwards the packet
* to it; if no matching SAP, drops the packet. Returns 0 or the return of
* llc_conn_send_ev (that may well result in the connection being
* destroyed)
* Sends data unit to station state machine.
*/
int llc_pdu_router(struct llc_sap *sap, struct sock* sk,
struct sk_buff *skb, u8 type)
static void llc_station_rcv(struct sk_buff *skb)
{
struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb);
int rc = 0;
struct llc_station *station = llc_station_get();
struct llc_station_state_ev *ev = llc_station_ev(skb);
if (!pdu->dsap) {
struct llc_station *station = llc_station_get();
struct llc_station_state_ev *ev = llc_station_ev(skb);
ev->type = LLC_STATION_EV_TYPE_PDU;
ev->data.pdu.reason = 0;
llc_station_state_process(station, skb);
}
ev->type = LLC_STATION_EV_TYPE_PDU;
ev->data.pdu.reason = 0;
llc_station_send_ev(station, skb);
} else if (type == LLC_TYPE_1) {
struct llc_sap_state_ev *ev = llc_sap_ev(skb);
ev->type = LLC_SAP_EV_TYPE_PDU;
ev->data.pdu.reason = 0;
llc_sap_send_ev(sap, skb);
} else if (type == LLC_TYPE_2) {
struct llc_conn_state_ev *ev = llc_conn_ev(skb);
struct llc_opt *llc = llc_sk(sk);
/**
* llc_conn_rcv - sends received pdus to the connection state machine
* @sk: current connection structure.
* @skb: received frame.
*
* Sends received pdus to the connection state machine.
*/
int llc_conn_rcv(struct sock* sk, struct sk_buff *skb)
{
struct llc_conn_state_ev *ev = llc_conn_ev(skb);
struct llc_opt *llc = llc_sk(sk);
if (!llc->dev)
llc->dev = skb->dev;
if (!llc->dev)
llc->dev = skb->dev;
ev->type = LLC_CONN_EV_TYPE_PDU;
ev->data.pdu.reason = 0;
return llc_conn_state_process(sk, skb);
}
ev->type = LLC_CONN_EV_TYPE_PDU;
ev->data.pdu.reason = 0;
rc = llc_conn_send_ev(sk, skb);
} else
rc = -EINVAL;
return rc;
/**
* llc_sap_rcv - sends received pdus to the sap state machine
* @sap: current sap component structure.
* @skb: received frame.
*
* Sends received pdus to the sap state machine.
*/
static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb)
{
struct llc_sap_state_ev *ev = llc_sap_ev(skb);
ev->type = LLC_SAP_EV_TYPE_PDU;
ev->data.pdu.reason = 0;
llc_sap_state_process(sap, skb);
}
/**
......
......@@ -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 @@ int llc_sock_init(struct sock* sk)
}
/**
* __llc_sock_alloc - Allocates LLC sock
* llc_sk_alloc - Allocates LLC sock
* @family: upper layer protocol family
* @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc)
*
* Allocates a LLC sock and initializes it. Returns the new LLC sock
* or %NULL if there's no memory available for one
*/
struct sock *__llc_sock_alloc(void)
struct sock *llc_sk_alloc(int family, int priority)
{
struct sock *sk = sk_alloc(PF_LLC, GFP_ATOMIC, 1, NULL);
struct sock *sk = sk_alloc(family, priority, 1, NULL);
MOD_INC_USE_COUNT;
if (!sk)
goto out;
if (llc_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 @@ static int llc_proc_get_info(char *bf, char **start, off_t offset, int length)
static struct packet_type llc_packet_type = {
.type = __constant_htons(ETH_P_802_2),
.func = mac_indicate,
.func = llc_rcv,
.data = (void *)1,
};
static struct packet_type llc_tr_packet_type = {
.type = __constant_htons(ETH_P_TR_802_2),
.func = mac_indicate,
.func = llc_rcv,
.data = (void *)1,
};
......@@ -585,7 +608,7 @@ static int __init llc_init(void)
skb_queue_head_init(&llc_main_station.mac_pdu_q);
skb_queue_head_init(&llc_main_station.ev_q.list);
spin_lock_init(&llc_main_station.ev_q.lock);
skb = alloc_skb(1, GFP_ATOMIC);
skb = alloc_skb(0, GFP_ATOMIC);
if (!skb)
goto err;
llc_build_offset_table();
......
......@@ -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;
}
/**
......
......@@ -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);
......
......@@ -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");
}
/**
......@@ -142,19 +142,6 @@ void llc_sap_send_pdu(struct llc_sap *sap, struct sk_buff *skb)
kfree_skb(skb);
}
/**
* llc_sap_free_ev - frees an sap event
* @sap: pointer to SAP
* @skb: released event
*/
static void llc_sap_free_ev(struct llc_sap *sap, struct sk_buff *skb)
{
struct llc_sap_state_ev *ev = llc_sap_ev(skb);
if (ev->type == LLC_SAP_EV_TYPE_PDU)
kfree_skb(skb);
}
/**
* llc_sap_next_state - finds transition, execs actions & change SAP state
* @sap: pointer to SAP
......@@ -206,7 +193,7 @@ static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap,
/* search thru events for this state until list exhausted or until
* its obvious the event is not valid for the current state
*/
for (next_trans = curr_state->transitions; next_trans [i]->ev; i++)
for (next_trans = curr_state->transitions; next_trans[i]->ev; i++)
if (!next_trans[i]->ev(sap, skb)) {
/* got event match; return it */
rc = next_trans[i];
......
......@@ -11,6 +11,7 @@
* connections.
*
* Copyright (c) 2001 by Jay Schulist <jschlst@samba.org>
* 2002 by Arnaldo Carvalho de Melo <acme@conectiva.com.br>
*
* This program can be redistributed or modified under the terms of the
* GNU General Public License as published by the Free Software Foundation.
......@@ -38,6 +39,7 @@
#include <net/llc_sap.h>
#include <net/llc_pdu.h>
#include <net/llc_conn.h>
#include <net/llc_mac.h>
#include <linux/llc.h>
#include <linux/if_arp.h>
#include <linux/rtnetlink.h>
......@@ -46,7 +48,6 @@
/* remember: uninitialized global data is zeroed because its in .bss */
static u16 llc_ui_sap_last_autoport = LLC_SAP_DYN_START;
static u16 llc_ui_sap_link_no_max[256];
static u8 llc_ui_addrany[IFHWADDRLEN];
static struct sockaddr_llc llc_ui_addrnull;
static struct proto_ops llc_ui_ops;
static struct sock *llc_ui_sockets;
......@@ -54,8 +55,16 @@ static rwlock_t llc_ui_sockets_lock = RW_LOCK_UNLOCKED;
static int llc_ui_indicate(struct llc_prim_if_block *prim);
static int llc_ui_confirm(struct llc_prim_if_block *prim);
static int llc_ui_wait_for_conn(struct sock *sk, int seconds);
static int llc_ui_wait_for_disc(struct sock *sk, int seconds);
static int llc_ui_wait_for_conn(struct sock *sk, int timeout);
static int llc_ui_wait_for_disc(struct sock *sk, int timeout);
static int llc_ui_wait_for_data(struct sock *sk, int timeout);
static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout);
#if 0
#define dprintk(args...) printk(KERN_DEBUG args)
#else
#define dprintk(args...)
#endif
/**
* llc_ui_next_link_no - return the next unused link number for a sap
......@@ -63,63 +72,20 @@ static int llc_ui_wait_for_disc(struct sock *sk, int seconds);
*
* Return the next unused link number for a given sap.
*/
static inline u16 llc_ui_next_link_no(int sap)
static __inline__ u16 llc_ui_next_link_no(int sap)
{
return llc_ui_sap_link_no_max[sap]++;
}
/**
* llc_ui_mac_match - determines if two mac addresses are the same
* @mac1: First mac address to compare.
* @mac2: Second mac address to compare.
*
* Determines if two given mac address are the same. Returns 0 if there
* is not a complete match up to len, 1 if a complete match up to len is
* found.
*/
static inline u8 llc_ui_mac_match(u8 *mac1, u8 *mac2)
{
return !memcmp(mac1, mac2, IFHWADDRLEN);
}
/**
* llc_ui_mac_null - determines if a address is a null mac address
* @mac: Mac address to test if null.
*
* Determines if a given address is a null mac address. Returns 0 if the
* address is not a null mac, 1 if the address is a null mac.
*/
static inline u8 llc_ui_mac_null(u8 *mac)
{
return !memcmp(mac, llc_ui_addrany, IFHWADDRLEN);
}
/**
* llc_ui_addr_null - determines if a address structure is null
* @addr: Address to test if null.
*/
static inline u8 llc_ui_addr_null(struct sockaddr_llc *addr)
static __inline__ u8 llc_ui_addr_null(struct sockaddr_llc *addr)
{
return !memcmp(addr, &llc_ui_addrnull, sizeof(*addr));
}
/**
* llc_ui_protocol_type - return eth protocol for ARP header type
* @arphrd: ARP header type.
*
* Given an ARP header type return the corresponding ethernet protocol.
* Returns 0 if ARP header type not supported or the corresponding
* ethernet protocol type.
*/
static inline u16 llc_ui_protocol_type(u16 arphrd)
{
u16 rc = htons(ETH_P_802_2);
if (arphrd == ARPHRD_IEEE802_TR)
rc = htons(ETH_P_TR_802_2);
return rc;
}
/**
* llc_ui_header_len - return length of llc header based on operation
* @sk: Socket which contains a valid llc socket type.
......@@ -129,7 +95,8 @@ static inline u16 llc_ui_protocol_type(u16 arphrd)
* operation the user would like to perform and the type of socket.
* Returns the correct llc header length.
*/
static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr)
static __inline__ u8 llc_ui_header_len(struct sock *sk,
struct sockaddr_llc *addr)
{
u8 rc = LLC_PDU_LEN_U;
......@@ -140,138 +107,33 @@ static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr)
return rc;
}
/**
* llc_ui_send_conn - send connect command for new llc2 connection
* @sap : Sap the socket is bound to.
* @addr: Source and destination fields provided by the user.
* @dev : Device which this connection should use.
* @link: Link number to assign to this connection.
*
* Send a connect command to the llc layer for a new llc2 connection.
* Returns 0 upon success, non-zero if action didn't succeed.
*/
static int llc_ui_send_conn(struct sock *sk, struct llc_sap *sap,
struct sockaddr_llc *addr,
struct net_device *dev, int link)
{
struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
union llc_u_prim_data prim_data;
struct llc_prim_if_block prim;
prim.data = &prim_data;
prim.sap = sap;
prim.prim = LLC_CONN_PRIM;
prim_data.conn.dev = dev;
prim_data.conn.link = link;
prim_data.conn.sk = NULL;
prim_data.conn.handler = sk;
prim_data.conn.pri = 0;
prim_data.conn.saddr.lsap = llc_ui->addr.sllc_ssap;
prim_data.conn.daddr.lsap = addr->sllc_dsap;
memcpy(prim_data.conn.saddr.mac, dev->dev_addr, IFHWADDRLEN);
memcpy(prim_data.conn.daddr.mac, addr->sllc_dmac, IFHWADDRLEN);
return sap->req(&prim);
}
/**
* llc_ui_send_disc - send disc command to llc layer
* @sk: Socket with valid llc information.
*
* Send a disconnect command to the llc layer for an established
* llc2 connection.
* Returns 0 upon success, non-zero if action did not succeed.
*/
static int llc_ui_send_disc(struct sock *sk)
{
struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
union llc_u_prim_data prim_data;
struct llc_prim_if_block prim;
int rc = 0;
if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED)
goto out;
sk->state = TCP_CLOSING;
prim.data = &prim_data;
prim.sap = llc_ui->sap;
prim.prim = LLC_DISC_PRIM;
prim_data.disc.sk = llc_ui->core_sk;
prim_data.disc.link = llc_ui->link;
rc = llc_ui->sap->req(&prim);
out:
return rc;
}
/**
* llc_ui_send_data - send data via reliable llc2 connection
* @sap: Sap the socket is bound to.
* @sk: Connection the socket is using.
* @skb: Data the user wishes to send.
* @addr: Source and destination fields provided by the user.
* @noblock: can we block waiting for data?
*
* Send data via reliable llc2 connection.
* Returns 0 upon success, non-zero if action did not succeed.
* Returns 0 upon success, non-zero if action did not succeed.
*/
static int llc_ui_send_data(struct llc_sap *sap, struct sock* sk,
struct 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 @@ static int llc_ui_create(struct socket *sock, int protocol)
static int llc_ui_release(struct socket *sock)
{
struct sock *sk = sock->sk;
struct llc_ui_opt *llc_ui;
struct llc_opt *llc;
if (!sk)
goto out;
llc_ui = llc_ui_sk(sk);
if (llc_ui->core_sk && !llc_ui_send_disc(sk))
llc_ui_wait_for_disc(sk, 255);
llc_ui_remove_socket(sk);
if (llc_ui->sap && !llc_ui_find_sap(llc_ui->sap->laddr.lsap))
llc_sap_close(llc_ui->sap);
sock_orphan(sk);
sock->sk = NULL;
if (!atomic_read(&sk->wmem_alloc) &&
!atomic_read(&sk->rmem_alloc) && sk->dead)
llc_ui_destroy_sk(sk);
else {
init_timer(&sk->timer);
sk->timer.expires = jiffies + SOCK_DESTROY_TIME;
sk->timer.function = llc_ui_destroy_timer;
sk->timer.data = (unsigned long)sk;
add_timer(&sk->timer);
sock_hold(sk);
lock_sock(sk);
llc = llc_sk(sk);
dprintk("%s: closing local(%02X) remote(%02X)\n", __FUNCTION__,
llc->laddr.lsap, llc->daddr.lsap);
if (!llc_send_disc(sk))
llc_ui_wait_for_disc(sk, sk->rcvtimeo);
release_sock(sk);
if (!sk->zapped) {
llc_sap_unassign_sock(llc->sap, sk);
llc_ui_remove_socket(sk);
}
if (llc->sap && list_empty(&llc->sap->sk_list.list))
llc_sap_close(llc->sap);
sock_put(sk);
llc_sk_free(sk);
out:
return 0;
}
......@@ -590,7 +412,7 @@ static int llc_ui_autoport(void)
static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
{
struct sock *sk = sock->sk;
struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
struct llc_opt *llc = llc_sk(sk);
struct llc_sap *sap;
struct net_device *dev = NULL;
int rc = -EINVAL;
......@@ -598,14 +420,14 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
if (!sk->zapped)
goto out;
/* bind to a specific mac, optional. */
if (!llc_ui_mac_null(addr->sllc_smac)) {
if (!llc_mac_null(addr->sllc_smac)) {
rtnl_lock();
dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac);
rtnl_unlock();
rc = -ENETUNREACH;
if (!dev)
goto out;
llc_ui->dev = dev;
llc->dev = dev;
}
/* bind to a specific sap, optional. */
if (!addr->sllc_ssap) {
......@@ -626,11 +448,11 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
struct sock *ask;
rc = -EUSERS; /* can't get exclusive use of sap */
if (!dev && llc_ui_mac_null(addr->sllc_mmac))
if (!dev && llc_mac_null(addr->sllc_mmac))
goto out;
memset(&laddr, 0, sizeof(laddr));
memset(&daddr, 0, sizeof(daddr));
if (!llc_ui_mac_null(addr->sllc_mmac)) {
if (!llc_mac_null(addr->sllc_mmac)) {
if (sk->type != SOCK_DGRAM) {
rc = -EOPNOTSUPP;
goto out;
......@@ -646,10 +468,16 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr)
goto out;
}
}
memcpy(&llc_ui->addr, addr, sizeof(*addr));
llc_ui->sap = sap;
llc->laddr.lsap = addr->sllc_ssap;
if (llc->dev)
memcpy(llc->laddr.mac, llc->dev->dev_addr, IFHWADDRLEN);
llc->daddr.lsap = addr->sllc_dsap;
memcpy(llc->daddr.mac, addr->sllc_dmac, IFHWADDRLEN);
memcpy(&llc->addr, addr, sizeof(llc->addr));
rc = sk->zapped = 0;
llc_ui_insert_socket(sk);
/* assign new connection to it's SAP */
llc_sap_assign_sock(sap, sk);
out:
return rc;
}
......@@ -678,6 +506,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
struct sock *sk = sock->sk;
int rc = -EINVAL;
dprintk("%s: binding %02X\n", __FUNCTION__, addr->sllc_ssap);
if (!sk->zapped || addrlen != sizeof(*addr))
goto out;
rc = -EAFNOSUPPORT;
......@@ -711,9 +540,9 @@ static int llc_ui_shutdown(struct socket *sock, int how)
rc = -EINVAL;
if (how != 2)
goto out;
rc = llc_ui_send_disc(sk);
rc = llc_send_disc(sk);
if (!rc)
llc_ui_wait_for_disc(sk, 255);
rc = llc_ui_wait_for_disc(sk, sk->rcvtimeo);
/* Wake up anyone sleeping in poll */
sk->state_change(sk);
out:
......@@ -739,7 +568,7 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
int addrlen, int flags)
{
struct sock *sk = sock->sk;
struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
struct llc_opt *llc = llc_sk(sk);
struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr;
struct net_device *dev;
int rc = -EINVAL;
......@@ -757,14 +586,15 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
if (rc)
goto out;
}
if (!llc_ui->dev) {
if (!llc->dev) {
rtnl_lock();
dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac);
rtnl_unlock();
if (!dev)
goto out;
llc->dev = dev;
} else
dev = llc_ui->dev;
dev = llc->dev;
if (sk->type != SOCK_STREAM)
goto out;
rc = -EALREADY;
......@@ -772,14 +602,18 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr,
goto out;
sock->state = SS_CONNECTING;
sk->state = TCP_SYN_SENT;
llc_ui->link = llc_ui_next_link_no(llc_ui->sap->laddr.lsap);
rc = llc_ui_send_conn(sk, llc_ui->sap, addr, dev, llc_ui->link);
llc->link = llc_ui_next_link_no(llc->sap->laddr.lsap);
rc = llc_establish_connection(sk, dev->dev_addr,
addr->sllc_dmac, addr->sllc_dsap);
if (rc) {
dprintk("%s: llc_ui_send_conn failed :-(\n", __FUNCTION__);
sock->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE;
goto out;
}
rc = llc_ui_wait_for_conn(sk, 255);
rc = llc_ui_wait_for_conn(sk, sk->rcvtimeo);
if (rc)
dprintk("%s: llc_ui_wait_for_conn failed=%d\n", __FUNCTION__, rc);
out:
release_sock(sk);
return rc;
......@@ -802,7 +636,7 @@ static int llc_ui_listen(struct socket *sock, int backlog)
if (sock->state != SS_UNCONNECTED)
goto out;
rc = -EOPNOTSUPP;
if (sk->type != SOCK_STREAM && sk->type != SOCK_SEQPACKET)
if (sk->type != SOCK_STREAM)
goto out;
rc = -EAGAIN;
if (sk->zapped)
......@@ -810,8 +644,6 @@ static int llc_ui_listen(struct socket *sock, int backlog)
rc = 0;
if (!(unsigned)backlog) /* BSDism */
backlog = 1;
if ((unsigned)backlog > SOMAXCONN)
backlog = SOMAXCONN;
sk->max_ack_backlog = backlog;
if (sk->state != TCP_LISTEN) {
sk->ack_backlog = 0;
......@@ -823,18 +655,43 @@ static int llc_ui_listen(struct socket *sock, int backlog)
return rc;
}
static int llc_ui_wait_for_disc(struct sock *sk, int seconds)
static int llc_ui_wait_for_disc(struct sock *sk, int timeout)
{
DECLARE_WAITQUEUE(wait, current);
int rc, timeout = seconds * HZ;
int rc;
add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
rc = -ERESTARTSYS;
if (signal_pending(current))
break;
rc = -EAGAIN;
if (!timeout)
break;
rc = 0;
if (sk->state != TCP_CLOSE)
if (sk->state != TCP_CLOSE) {
release_sock(sk);
timeout = schedule_timeout(timeout);
else
lock_sock(sk);
} else
break;
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(sk->sleep, &wait);
return rc;
}
static int llc_ui_wait_for_conn(struct sock *sk, int timeout)
{
DECLARE_WAITQUEUE(wait, current);
int rc;
add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
rc = -EAGAIN;
if (sk->state == TCP_CLOSE)
break;
rc = -ERESTARTSYS;
if (signal_pending(current))
......@@ -842,31 +699,60 @@ static int llc_ui_wait_for_disc(struct sock *sk, int seconds)
rc = -EAGAIN;
if (!timeout)
break;
rc = 0;
if (sk->state != TCP_ESTABLISHED) {
release_sock(sk);
timeout = schedule_timeout(timeout);
lock_sock(sk);
} else
break;
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(sk->sleep, &wait);
return rc;
}
static int llc_ui_wait_for_conn(struct sock *sk, int seconds)
static int llc_ui_wait_for_data(struct sock *sk, int timeout)
{
struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
DECLARE_WAITQUEUE(wait, current);
int rc, timeout = seconds * HZ;
int rc = 0;
add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) {
__set_current_state(TASK_INTERRUPTIBLE);
if (sk->shutdown & RCV_SHUTDOWN)
break;
rc = -ERESTARTSYS;
if (signal_pending(current))
break;
rc = -EAGAIN;
if (!timeout)
break;
rc = 0;
if (sk->state != TCP_ESTABLISHED)
if (skb_queue_empty(&sk->receive_queue)) {
release_sock(sk);
timeout = schedule_timeout(timeout);
if (sk->state == TCP_ESTABLISHED) {
if (!llc_ui->core_sk)
rc = -EAGAIN;
lock_sock(sk);
} else
break;
}
rc = -EAGAIN;
if (sk->state == TCP_CLOSE)
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(sk->sleep, &wait);
return rc;
}
static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout)
{
DECLARE_WAITQUEUE(wait, current);
struct llc_opt *llc = llc_sk(sk);
int rc;
add_wait_queue_exclusive(sk->sleep, &wait);
for (;;) {
dprintk("%s: looping...\n", __FUNCTION__);
__set_current_state(TASK_INTERRUPTIBLE);
rc = -ENOTCONN;
if (sk->shutdown & RCV_SHUTDOWN)
break;
rc = -ERESTARTSYS;
if (signal_pending(current))
......@@ -874,6 +760,13 @@ static int llc_ui_wait_for_conn(struct sock *sk, int seconds)
rc = -EAGAIN;
if (!timeout)
break;
rc = 0;
if (llc_data_accept_state(llc->state) || llc->p_flag) {
release_sock(sk);
timeout = schedule_timeout(timeout);
lock_sock(sk);
} else
break;
}
__set_current_state(TASK_RUNNING);
remove_wait_queue(sk->sleep, &wait);
......@@ -892,63 +785,48 @@ static int llc_ui_wait_for_conn(struct sock *sk, int seconds)
static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags)
{
struct sock *sk = sock->sk, *newsk;
struct llc_ui_opt *llc_ui, *newllc_ui;
struct llc_opt *newllc_core;
struct llc_opt *llc, *newllc;
struct sk_buff *skb;
int rc = -EOPNOTSUPP;
dprintk("%s: accepting on %02X\n", __FUNCTION__, llc_sk(sk)->addr.sllc_ssap);
lock_sock(sk);
if (sk->type != SOCK_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);
......@@ -1470,35 +1274,6 @@ static void llc_ui_ind_data(struct llc_prim_if_block *prim)
out:;
}
/**
* llc_ui_ind_disc - handle DISC indication
* @prim: Primitive block provided by the llc layer.
*
* handle DISC indication.
*/
static void llc_ui_ind_disc(struct llc_prim_if_block *prim)
{
struct llc_prim_disc *prim_data = &prim->data->disc;
struct sock* sk = llc_sk(prim_data->sk)->handler;
if (!sk)
goto out;
sock_hold(sk);
if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED)
goto out_put;
llc_ui_sk(sk)->core_sk = NULL;
sk->shutdown = SHUTDOWN_MASK;
sk->socket->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE;
if (!sk->dead) {
sk->state_change(sk);
sk->dead = 1;
}
out_put:
sock_put(sk);
out:;
}
/**
* llc_ui_indicate - LLC user interface hook into the LLC layer.
* @prim: Primitive block provided by the llc layer.
......@@ -1517,91 +1292,23 @@ static int llc_ui_indicate(struct llc_prim_if_block *prim)
case LLC_DATAUNIT_PRIM:
llc_ui_ind_dataunit(prim); break;
case LLC_CONN_PRIM:
llc_ui_ind_conn(prim); break;
dprintk("%s: shouldn't happen, LLC_CONN_PRIM "
"is gone for ->ind()...\n", __FUNCTION__);
break;
case LLC_DATA_PRIM:
llc_ui_ind_data(prim); break;
dprintk("%s: shouldn't happen, LLC_DATA_PRIM "
"is gone for ->ind()...\n", __FUNCTION__);
break;
case LLC_DISC_PRIM:
llc_ui_ind_disc(prim); break;
dprintk("%s: shouldn't happen, LLC_DISC_PRIM "
"is gone for ->ind()...\n", __FUNCTION__);
break;
case LLC_RESET_PRIM:
case LLC_FLOWCONTROL_PRIM:
default: break;
}
return 0;
}
/**
* llc_ui_conf_conn - handle CONN confirm.
* @prim: Primitive block provided by the llc layer.
*
* handle CONN confirm.
*/
static void llc_ui_conf_conn(struct llc_prim_if_block *prim)
{
struct llc_prim_conn *prim_data = &prim->data->conn;
struct llc_opt *llc_core = llc_sk(prim_data->sk);
struct sock* sk = llc_core->handler;
struct llc_ui_opt *llc_ui = llc_ui_sk(sk);
if (!sk)
goto out;
sock_hold(sk);
if (sk->type != SOCK_STREAM || sk->state != TCP_SYN_SENT)
goto out_put;
if (!prim->data->conn.status) {
sk->socket->state = SS_CONNECTED;
sk->state = TCP_ESTABLISHED;
llc_ui->core_sk = prim_data->sk;
} else {
sk->socket->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE;
llc_ui->core_sk = NULL;
}
sk->state_change(sk);
out_put:
sock_put(sk);
out:;
}
/**
* llc_ui_conf_data - handle DATA confirm.
* @prim: Primitive block provided by the llc layer.
*
* handle DATA confirm.
*/
static void llc_ui_conf_data(struct llc_prim_if_block *prim)
{
struct llc_prim_data *prim_data = &prim->data->data;
struct sock* sk = llc_sk(prim_data->sk)->handler;
if (sk)
wake_up(sk->sleep);
}
/**
* llc_ui_conf_disc - handle DISC confirm.
* @prim: Primitive block provided by the llc layer.
*
* handle DISC confirm.
*/
static void llc_ui_conf_disc(struct llc_prim_if_block *prim)
{
struct llc_prim_disc *prim_data = &prim->data->disc;
struct sock* sk = llc_sk(prim_data->sk)->handler;
if (!sk)
goto out;
sock_hold(sk);
if (sk->type != SOCK_STREAM || sk->state != TCP_CLOSING)
goto out_put;
llc_ui_sk(sk)->core_sk = NULL;
sk->socket->state = SS_UNCONNECTED;
sk->state = TCP_CLOSE;
sk->state_change(sk);
out_put:
sock_put(sk);
out:;
}
/**
* llc_ui_confirm - LLC user interface hook into the LLC layer
* @prim: Primitive block provided by the llc layer.
......@@ -1614,14 +1321,20 @@ static int llc_ui_confirm(struct llc_prim_if_block *prim)
{
switch (prim->prim) {
case LLC_CONN_PRIM:
llc_ui_conf_conn(prim); break;
dprintk("%s: shouldn't happen, LLC_CONN_PRIM "
"is gone for ->conf()...\n", __FUNCTION__);
break;
case LLC_DATA_PRIM:
llc_ui_conf_data(prim); break;
dprintk("%s: shouldn't happen, LLC_DATA_PRIM "
"is gone for ->conf()...\n", __FUNCTION__);
break;
case LLC_DISC_PRIM:
llc_ui_conf_disc(prim); break;
dprintk("%s: shouldn't happen, LLC_DISC_PRIM "
"is gone for ->conf()...\n", __FUNCTION__);
break;
case LLC_RESET_PRIM: break;
default:
printk(KERN_ERR "%s: unknown prim %d\n", __FUNCTION__,
printk(KERN_ERR "%s: prim not supported%d\n", __FUNCTION__,
prim->prim);
break;
}
......@@ -1651,46 +1364,42 @@ static int llc_ui_get_info(char *buffer, char **start, off_t offset, int length)
off_t pos = 0;
off_t begin = 0;
struct sock *s;
int len = sprintf(buffer, "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)
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment