diff options
| author | Linus Torvalds <torvalds@home.transmeta.com> | 2002-09-13 04:10:14 -0700 |
|---|---|---|
| committer | Linus Torvalds <torvalds@home.transmeta.com> | 2002-09-13 04:10:14 -0700 |
| commit | d038b8c52e647b144fea7a032cae78677d0c819e (patch) | |
| tree | f781b5f3146d7dd93b1dee81c116efa6e7892296 | |
| parent | d1a75a97b0d3b9bc4e6a95f4e7854e7a7a986976 (diff) | |
| parent | 1a2c129e137343fed08fd9c61b353cabc6b72aaa (diff) | |
Merge master.kernel.org:/home/davem/BK/net-2.5
into home.transmeta.com:/home/torvalds/v2.5/linux
| -rw-r--r-- | drivers/net/tg3.c | 1096 | ||||
| -rw-r--r-- | drivers/net/tg3.h | 59 | ||||
| -rw-r--r-- | drivers/pci/pci.ids | 1 | ||||
| -rw-r--r-- | include/linux/llc.h | 11 | ||||
| -rw-r--r-- | include/linux/pci_ids.h | 1 | ||||
| -rw-r--r-- | include/net/llc_c_st.h | 12 | ||||
| -rw-r--r-- | include/net/llc_conn.h | 73 | ||||
| -rw-r--r-- | include/net/llc_if.h | 68 | ||||
| -rw-r--r-- | include/net/llc_mac.h | 41 | ||||
| -rw-r--r-- | include/net/llc_main.h | 4 | ||||
| -rw-r--r-- | include/net/llc_pdu.h | 56 | ||||
| -rw-r--r-- | include/net/llc_sap.h | 4 | ||||
| -rw-r--r-- | net/8021q/vlan.c | 2 | ||||
| -rw-r--r-- | net/core/dev.c | 10 | ||||
| -rw-r--r-- | net/ipv4/ip_options.c | 2 | ||||
| -rw-r--r-- | net/ipv4/tcp_input.c | 35 | ||||
| -rw-r--r-- | net/llc/llc_actn.c | 4 | ||||
| -rw-r--r-- | net/llc/llc_c_ac.c | 153 | ||||
| -rw-r--r-- | net/llc/llc_c_ev.c | 20 | ||||
| -rw-r--r-- | net/llc/llc_conn.c | 216 | ||||
| -rw-r--r-- | net/llc/llc_if.c | 441 | ||||
| -rw-r--r-- | net/llc/llc_mac.c | 169 | ||||
| -rw-r--r-- | net/llc/llc_main.c | 85 | ||||
| -rw-r--r-- | net/llc/llc_pdu.c | 130 | ||||
| -rw-r--r-- | net/llc/llc_s_ac.c | 23 | ||||
| -rw-r--r-- | net/llc/llc_sap.c | 33 | ||||
| -rw-r--r-- | net/llc/llc_sock.c | 963 |
27 files changed, 2054 insertions, 1658 deletions
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c index bf08bba649eb..122b5aa10204 100644 --- a/drivers/net/tg3.c +++ b/drivers/net/tg3.c @@ -48,12 +48,19 @@ #define TG3_VLAN_TAG_USED 0 #endif +#ifdef NETIF_F_TSO +/* XXX some bug in tso firmware hangs tx cpu, disabled until fixed */ +#define TG3_DO_TSO 0 +#else +#define TG3_DO_TSO 0 +#endif + #include "tg3.h" #define DRV_MODULE_NAME "tg3" #define PFX DRV_MODULE_NAME ": " -#define DRV_MODULE_VERSION "1.0" -#define DRV_MODULE_RELDATE "Jul 19, 2002" +#define DRV_MODULE_VERSION "1.1" +#define DRV_MODULE_RELDATE "Aug 30, 2002" #define TG3_DEF_MAC_MODE 0 #define TG3_DEF_RX_MODE 0 @@ -142,6 +149,8 @@ static struct pci_device_id tg3_pci_tbl[] __devinitdata = { PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5703, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, + { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5704, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702FE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, { PCI_VENDOR_ID_BROADCOM, PCI_DEVICE_ID_TIGON3_5702X, @@ -212,6 +221,7 @@ static void tg3_disable_ints(struct tg3 *tp) tw32(TG3PCI_MISC_HOST_CTRL, (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT)); tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001); + tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); } static void tg3_enable_ints(struct tg3 *tp) @@ -220,9 +230,11 @@ static void tg3_enable_ints(struct tg3 *tp) (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT)); tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000); - if (tp->hw_status->status & SD_STATUS_UPDATED) + if (tp->hw_status->status & SD_STATUS_UPDATED) { tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); + } + tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); } #define PHY_BUSY_LOOPS 5000 @@ -235,6 +247,7 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val) if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { tw32(MAC_MI_MODE, (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL)); + tr32(MAC_MI_MODE); udelay(40); } @@ -247,9 +260,11 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val) frame_val |= (MI_COM_CMD_READ | MI_COM_START); tw32(MAC_MI_COM, frame_val); + tr32(MAC_MI_COM); loops = PHY_BUSY_LOOPS; while (loops-- > 0) { + udelay(10); frame_val = tr32(MAC_MI_COM); if ((frame_val & MI_COM_BUSY) == 0) { @@ -257,7 +272,6 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val) frame_val = tr32(MAC_MI_COM); break; } - udelay(10); } ret = -EBUSY; @@ -268,6 +282,7 @@ static int tg3_readphy(struct tg3 *tp, int reg, u32 *val) if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { tw32(MAC_MI_MODE, tp->mi_mode); + tr32(MAC_MI_MODE); udelay(40); } @@ -282,6 +297,7 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val) if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { tw32(MAC_MI_MODE, (tp->mi_mode & ~MAC_MI_MODE_AUTO_POLL)); + tr32(MAC_MI_MODE); udelay(40); } @@ -293,16 +309,17 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val) frame_val |= (MI_COM_CMD_WRITE | MI_COM_START); tw32(MAC_MI_COM, frame_val); + tr32(MAC_MI_COM); loops = PHY_BUSY_LOOPS; while (loops-- > 0) { + udelay(10); frame_val = tr32(MAC_MI_COM); if ((frame_val & MI_COM_BUSY) == 0) { udelay(5); frame_val = tr32(MAC_MI_COM); break; } - udelay(10); } ret = -EBUSY; @@ -311,6 +328,7 @@ static int tg3_writephy(struct tg3 *tp, int reg, u32 val) if ((tp->mi_mode & MAC_MI_MODE_AUTO_POLL) != 0) { tw32(MAC_MI_MODE, tp->mi_mode); + tr32(MAC_MI_MODE); udelay(40); } @@ -388,7 +406,9 @@ static int tg3_set_power_state(struct tg3 *tp, int state) pm + PCI_PM_CTRL, power_control); tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl); - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02); + tr32(GRC_LOCAL_CTRL); + udelay(100); + return 0; case 1: @@ -424,6 +444,7 @@ static int tg3_set_power_state(struct tg3 *tp, int state) } tp->link_config.speed = SPEED_10; + tp->link_config.duplex = DUPLEX_HALF; tp->link_config.autoneg = AUTONEG_ENABLE; tg3_setup_phy(tp); @@ -435,51 +456,108 @@ static int tg3_set_power_state(struct tg3 *tp, int state) u32 mac_mode; tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x5a); + udelay(40); + + mac_mode = MAC_MODE_PORT_MODE_MII; - mac_mode = MAC_MODE_PORT_MODE_MII | - MAC_MODE_LINK_POLARITY; + if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 || + !(tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB)) + mac_mode |= MAC_MODE_LINK_POLARITY; if (((power_caps & PCI_PM_CAP_PME_D3cold) && (tp->tg3_flags & TG3_FLAG_WOL_ENABLE))) mac_mode |= MAC_MODE_MAGIC_PKT_ENABLE; tw32(MAC_MODE, mac_mode); + tr32(MAC_MODE); + udelay(40); + tw32(MAC_RX_MODE, RX_MODE_ENABLE); + tr32(MAC_RX_MODE); + udelay(10); } if (tp->tg3_flags & TG3_FLAG_WOL_SPEED_100MB) { - tw32(TG3PCI_CLOCK_CTRL, - (CLOCK_CTRL_RXCLK_DISABLE | - CLOCK_CTRL_TXCLK_DISABLE | - CLOCK_CTRL_ALTCLK)); - tw32(TG3PCI_CLOCK_CTRL, - (CLOCK_CTRL_RXCLK_DISABLE | - CLOCK_CTRL_TXCLK_DISABLE | - CLOCK_CTRL_44MHZ_CORE)); - tw32(TG3PCI_CLOCK_CTRL, - (CLOCK_CTRL_RXCLK_DISABLE | - CLOCK_CTRL_TXCLK_DISABLE | - CLOCK_CTRL_ALTCLK | - CLOCK_CTRL_44MHZ_CORE)); + u32 base_val; + + base_val = 0; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) + base_val |= (CLOCK_CTRL_RXCLK_DISABLE | + CLOCK_CTRL_TXCLK_DISABLE); + + tw32(TG3PCI_CLOCK_CTRL, base_val | + CLOCK_CTRL_ALTCLK); + tr32(TG3PCI_CLOCK_CTRL); + udelay(40); + + tw32(TG3PCI_CLOCK_CTRL, base_val | + CLOCK_CTRL_ALTCLK | + CLOCK_CTRL_44MHZ_CORE); + tr32(TG3PCI_CLOCK_CTRL); + udelay(40); + + tw32(TG3PCI_CLOCK_CTRL, base_val | + CLOCK_CTRL_44MHZ_CORE); + tr32(TG3PCI_CLOCK_CTRL); + udelay(40); } else { - tw32(TG3PCI_CLOCK_CTRL, - (CLOCK_CTRL_RXCLK_DISABLE | - CLOCK_CTRL_TXCLK_DISABLE | - CLOCK_CTRL_ALTCLK | - CLOCK_CTRL_PWRDOWN_PLL133)); + u32 base_val; + + base_val = 0; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) + base_val |= (CLOCK_CTRL_RXCLK_DISABLE | + CLOCK_CTRL_TXCLK_DISABLE); + + tw32(TG3PCI_CLOCK_CTRL, base_val | + CLOCK_CTRL_ALTCLK | + CLOCK_CTRL_PWRDOWN_PLL133); + tr32(TG3PCI_CLOCK_CTRL); + udelay(40); } - udelay(40); - - if ((power_caps & PCI_PM_CAP_PME_D3cold) && + if (!(tp->tg3_flags & TG3_FLAG_EEPROM_WRITE_PROT) && (tp->tg3_flags & TG3_FLAG_WOL_ENABLE)) { - /* Move to auxilliary power. */ - tw32(GRC_LOCAL_CTRL, - (GRC_LCLCTRL_GPIO_OE0 | - GRC_LCLCTRL_GPIO_OE1 | - GRC_LCLCTRL_GPIO_OE2 | - GRC_LCLCTRL_GPIO_OUTPUT0 | - GRC_LCLCTRL_GPIO_OUTPUT1)); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 || + GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5701) { + tw32(GRC_LOCAL_CTRL, + (GRC_LCLCTRL_GPIO_OE0 | + GRC_LCLCTRL_GPIO_OE1 | + GRC_LCLCTRL_GPIO_OE2 | + GRC_LCLCTRL_GPIO_OUTPUT0 | + GRC_LCLCTRL_GPIO_OUTPUT1)); + tr32(GRC_LOCAL_CTRL); + udelay(100); + } else { + tw32(GRC_LOCAL_CTRL, + (GRC_LCLCTRL_GPIO_OE0 | + GRC_LCLCTRL_GPIO_OE1 | + GRC_LCLCTRL_GPIO_OE2 | + GRC_LCLCTRL_GPIO_OUTPUT1 | + GRC_LCLCTRL_GPIO_OUTPUT2)); + tr32(GRC_LOCAL_CTRL); + udelay(100); + + tw32(GRC_LOCAL_CTRL, + (GRC_LCLCTRL_GPIO_OE0 | + GRC_LCLCTRL_GPIO_OE1 | + GRC_LCLCTRL_GPIO_OE2 | + GRC_LCLCTRL_GPIO_OUTPUT0 | + GRC_LCLCTRL_GPIO_OUTPUT1 | + GRC_LCLCTRL_GPIO_OUTPUT2)); + tr32(GRC_LOCAL_CTRL); + udelay(100); + + tw32(GRC_LOCAL_CTRL, + (GRC_LCLCTRL_GPIO_OE0 | + GRC_LCLCTRL_GPIO_OE1 | + GRC_LCLCTRL_GPIO_OE2 | + GRC_LCLCTRL_GPIO_OUTPUT0 | + GRC_LCLCTRL_GPIO_OUTPUT1)); + tr32(GRC_LOCAL_CTRL); + udelay(100); + } } /* Finally, set the new power state. */ @@ -636,8 +714,9 @@ static int tg3_phy_copper_begin(struct tg3 *tp, int wait_for_link) new_adv |= MII_TG3_CTRL_ADV_1000_HALF; if (tp->link_config.advertising & ADVERTISED_1000baseT_Full) new_adv |= MII_TG3_CTRL_ADV_1000_FULL; - if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || - tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) + if (!(tp->tg3_flags & TG3_FLAG_10_100_ONLY) && + (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || + tp->pci_chip_rev_id == CHIPREV_ID_5701_B0)) new_adv |= (MII_TG3_CTRL_AS_MASTER | MII_TG3_CTRL_ENABLE_AS_MASTER); tg3_writephy(tp, MII_TG3_CTRL, new_adv); @@ -787,11 +866,16 @@ static int tg3_setup_copper_phy(struct tg3 *tp) tw32(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)); + tr32(MAC_STATUS); + udelay(40); tp->mi_mode = MAC_MI_MODE_BASE; tw32(MAC_MI_MODE, tp->mi_mode); + tr32(MAC_MI_MODE); udelay(40); + tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x02); + if ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401) { tg3_readphy(tp, MII_BMSR, &bmsr); tg3_readphy(tp, MII_BMSR, &bmsr); @@ -968,10 +1052,13 @@ static int tg3_setup_copper_phy(struct tg3 *tp) tp->pci_chip_rev_id == CHIPREV_ID_5700_ALTIMA) { tp->mi_mode |= MAC_MI_MODE_AUTO_POLL; tw32(MAC_MI_MODE, tp->mi_mode); + tr32(MAC_MI_MODE); udelay(40); } tw32(MAC_MODE, tp->mac_mode); + tr32(MAC_MODE); + udelay(40); if (tp->tg3_flags & (TG3_FLAG_USE_LINKCHG_REG | @@ -981,6 +1068,8 @@ static int tg3_setup_copper_phy(struct tg3 *tp) } else { tw32(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); } + tr32(MAC_EVENT); + udelay(40); if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700 && current_link_up == 1 && @@ -991,6 +1080,8 @@ static int tg3_setup_copper_phy(struct tg3 *tp) tw32(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)); + tr32(MAC_STATUS); + udelay(40); tg3_write_mem(tp, NIC_SRAM_FIRMWARE_MBOX, NIC_SRAM_FIRMWARE_MBOX_MAGIC2); @@ -1152,6 +1243,9 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp, tw32(MAC_TX_AUTO_NEG, 0); tp->mac_mode |= MAC_MODE_SEND_CONFIGS; tw32(MAC_MODE, tp->mac_mode); + tr32(MAC_MODE); + udelay(40); + ret = ANEG_TIMER_ENAB; ap->state = ANEG_STATE_RESTART; @@ -1175,6 +1269,8 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp, tw32(MAC_TX_AUTO_NEG, ap->txconfig); tp->mac_mode |= MAC_MODE_SEND_CONFIGS; tw32(MAC_MODE, tp->mac_mode); + tr32(MAC_MODE); + udelay(40); ap->state = ANEG_STATE_ABILITY_DETECT; break; @@ -1190,6 +1286,8 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp, tw32(MAC_TX_AUTO_NEG, ap->txconfig); tp->mac_mode |= MAC_MODE_SEND_CONFIGS; tw32(MAC_MODE, tp->mac_mode); + tr32(MAC_MODE); + udelay(40); ap->state = ANEG_STATE_ACK_DETECT; @@ -1275,6 +1373,8 @@ static int tg3_fiber_aneg_smachine(struct tg3 *tp, ap->link_time = ap->cur_time; tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS; tw32(MAC_MODE, tp->mac_mode); + tr32(MAC_MODE); + udelay(40); ap->state = ANEG_STATE_IDLE_DETECT; ret = ANEG_TIMER_ENAB; @@ -1331,6 +1431,7 @@ static int tg3_setup_fiber_phy(struct tg3 *tp) tp->mac_mode &= ~(MAC_MODE_PORT_MODE_MASK | MAC_MODE_HALF_DUPLEX); tp->mac_mode |= MAC_MODE_PORT_MODE_TBI; tw32(MAC_MODE, tp->mac_mode); + tr32(MAC_MODE); udelay(40); /* Reset when initting first time or we have a link. */ @@ -1381,6 +1482,8 @@ static int tg3_setup_fiber_phy(struct tg3 *tp) tw32(MAC_EVENT, MAC_EVENT_LNKSTATE_CHANGED); else tw32(MAC_EVENT, 0); + tr32(MAC_EVENT); + udelay(40); current_link_up = 0; if (tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) { @@ -1398,9 +1501,12 @@ static int tg3_setup_fiber_phy(struct tg3 *tp) tmp = tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK; tw32(MAC_MODE, tmp | MAC_MODE_PORT_MODE_GMII); - udelay(20); + tr32(MAC_MODE); + udelay(40); tw32(MAC_MODE, tp->mac_mode | MAC_MODE_SEND_CONFIGS); + tr32(MAC_MODE); + udelay(40); aninfo.state = ANEG_STATE_UNKNOWN; aninfo.cur_time = 0; @@ -1416,6 +1522,8 @@ static int tg3_setup_fiber_phy(struct tg3 *tp) tp->mac_mode &= ~MAC_MODE_SEND_CONFIGS; tw32(MAC_MODE, tp->mac_mode); + tr32(MAC_MODE); + udelay(40); if (status == ANEG_DONE && (aninfo.flags & @@ -1441,8 +1549,8 @@ static int tg3_setup_fiber_phy(struct tg3 *tp) tw32(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)); - - udelay(20); + tr32(MAC_STATUS); + udelay(40); if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)) == 0) @@ -1460,6 +1568,8 @@ static int tg3_setup_fiber_phy(struct tg3 *tp) tp->mac_mode &= ~MAC_MODE_LINK_POLARITY; tw32(MAC_MODE, tp->mac_mode); + tr32(MAC_MODE); + udelay(40); tp->hw_status->status = (SD_STATUS_UPDATED | @@ -1470,8 +1580,8 @@ static int tg3_setup_fiber_phy(struct tg3 *tp) tw32(MAC_STATUS, (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)); - - udelay(20); + tr32(MAC_STATUS); + udelay(40); if ((tr32(MAC_STATUS) & (MAC_STATUS_SYNC_CHANGED | MAC_STATUS_CFG_CHANGED)) == 0) @@ -1507,9 +1617,12 @@ static int tg3_setup_fiber_phy(struct tg3 *tp) if ((tr32(MAC_STATUS) & MAC_STATUS_PCS_SYNCED) == 0) { tw32(MAC_MODE, tp->mac_mode | MAC_MODE_LINK_POLARITY); + tr32(MAC_MODE); + udelay(40); if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) { - udelay(1); tw32(MAC_MODE, tp->mac_mode); + tr32(MAC_MODE); + udelay(40); } } @@ -1551,7 +1664,7 @@ static void tg3_tx(struct tg3 *tp) u32 sw_idx = tp->tx_cons; while (sw_idx != hw_idx) { - struct ring_info *ri = &tp->tx_buffers[sw_idx]; + struct tx_ring_info *ri = &tp->tx_buffers[sw_idx]; struct sk_buff *skb = ri->skb; int i; @@ -1881,23 +1994,31 @@ next_pkt_nopost: tp->rx_rcb_ptr = rx_rcb_ptr; tw32_mailbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, (rx_rcb_ptr % TG3_RX_RCB_RING_SIZE)); + if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + tr32(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW); /* Refill RX ring(s). */ if (work_mask & RXD_OPAQUE_RING_STD) { sw_idx = tp->rx_std_ptr % TG3_RX_RING_SIZE; tw32_mailbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW, sw_idx); + if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + tr32(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW); } if (work_mask & RXD_OPAQUE_RING_JUMBO) { sw_idx = tp->rx_jumbo_ptr % TG3_RX_JUMBO_RING_SIZE; tw32_mailbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, sw_idx); + if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + tr32(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW); } #if TG3_MINI_RING_WORKS if (work_mask & RXD_OPAQUE_RING_MINI) { sw_idx = tp->rx_mini_ptr % TG3_RX_MINI_RING_SIZE; tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW, sw_idx); + if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + tr32(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW); } #endif @@ -1974,6 +2095,9 @@ static __inline__ void tg3_interrupt_main_work(struct net_device *dev, struct tg return; if (netif_rx_schedule_prep(dev)) { + /* NOTE: This write is posted by the readback of + * the mailbox register done by our caller. + */ tw32(TG3PCI_MISC_HOST_CTRL, (tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT)); __netif_rx_schedule(dev); @@ -1988,8 +2112,9 @@ static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs) struct net_device *dev = dev_id; struct tg3 *tp = dev->priv; struct tg3_hw_status *sblk = tp->hw_status; + unsigned long flags; - spin_lock(&tp->lock); + spin_lock_irqsave(&tp->lock, flags); if (sblk->status & SD_STATUS_UPDATED) { tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, @@ -2003,7 +2128,7 @@ static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs) tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); } - spin_unlock(&tp->lock); + spin_unlock_irqrestore(&tp->lock, flags); } static void tg3_init_rings(struct tg3 *); @@ -2055,11 +2180,11 @@ static void tg3_set_txd_addr(struct tg3 *tp, int entry, dma_addr_t mapping) } #endif -static void tg3_set_txd(struct tg3 *, int, dma_addr_t, int, u32, int); +static void tg3_set_txd(struct tg3 *, int, dma_addr_t, int, u32, u32); static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, u32 guilty_entry, int guilty_len, - u32 last_plus_one, u32 *start) + u32 last_plus_one, u32 *start, u32 mss) { dma_addr_t new_addr; u32 entry = *start; @@ -2112,7 +2237,7 @@ static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, PCI_DMA_TODEVICE); tg3_set_txd(tp, entry, new_addr, new_skb->len, (skb->ip_summed == CHECKSUM_HW) ? - TXD_FLAG_TCPUDP_CSUM : 0, 1); + TXD_FLAG_TCPUDP_CSUM : 0, 1 | (mss << 1)); *start = NEXT_TX(entry); /* Now clean up the sw ring entries. */ @@ -2144,30 +2269,28 @@ static int tigon3_4gb_hwbug_workaround(struct tg3 *tp, struct sk_buff *skb, static void tg3_set_txd(struct tg3 *tp, int entry, dma_addr_t mapping, int len, u32 flags, - int is_end) + u32 mss_and_is_end) { -#if TG3_VLAN_TAG_USED - u16 vlan_tag = 0; -#endif + int is_end = (mss_and_is_end & 0x1); + u32 mss = (mss_and_is_end >> 1); + u32 vlan_tag = 0; if (is_end) flags |= TXD_FLAG_END; -#if TG3_VLAN_TAG_USED if (flags & TXD_FLAG_VLAN) { vlan_tag = flags >> 16; flags &= 0xffff; } -#endif + vlan_tag |= (mss << TXD_MSS_SHIFT); if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { struct tg3_tx_buffer_desc *txd = &tp->tx_ring[entry]; txd->addr_hi = ((u64) mapping >> 32); txd->addr_lo = ((u64) mapping & 0xffffffff); txd->len_flags = (len << TXD_LEN_SHIFT) | flags; -#if TG3_VLAN_TAG_USED txd->vlan_tag = vlan_tag << TXD_VLAN_TAG_SHIFT; -#endif } else { + struct tx_ring_info *txr = &tp->tx_buffers[entry]; unsigned long txd; txd = (tp->regs + @@ -2183,9 +2306,10 @@ static void tg3_set_txd(struct tg3 *tp, int entry, writel(((u64) mapping & 0xffffffff), txd + TXD_ADDR + TG3_64BIT_REG_LOW); writel(len << TXD_LEN_SHIFT | flags, txd + TXD_LEN_FLAGS); -#if TG3_VLAN_TAG_USED - writel(vlan_tag << TXD_VLAN_TAG_SHIFT, txd + TXD_VLAN_TAG); -#endif + if (txr->prev_vlan_tag != vlan_tag) { + writel(vlan_tag << TXD_VLAN_TAG_SHIFT, txd + TXD_VLAN_TAG); + txr->prev_vlan_tag = vlan_tag; + } } } @@ -2203,7 +2327,7 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev) struct tg3 *tp = dev->priv; dma_addr_t mapping; unsigned int i; - u32 len, entry, base_flags; + u32 len, entry, base_flags, mss; int would_hit_hwbug; len = (skb->len - skb->data_len); @@ -2227,6 +2351,13 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev) base_flags = 0; if (skb->ip_summed == CHECKSUM_HW) base_flags |= TXD_FLAG_TCPUDP_CSUM; +#if TG3_DO_TSO != 0 + if ((mss = skb_shinfo(skb)->tso_size) != 0) + base_flags |= (TXD_FLAG_CPU_PRE_DMA | + TXD_FLAG_CPU_POST_DMA); +#else + mss = 0; +#endif #if TG3_VLAN_TAG_USED if (tp->vlgrp != NULL && vlan_tx_tag_present(skb)) base_flags |= (TXD_FLAG_VLAN | @@ -2245,7 +2376,7 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev) would_hit_hwbug = entry + 1; tg3_set_txd(tp, entry, mapping, len, base_flags, - (skb_shinfo(skb)->nr_frags == 0)); + (skb_shinfo(skb)->nr_frags == 0) | (mss << 1)); entry = NEXT_TX(entry); @@ -2274,7 +2405,7 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev) } tg3_set_txd(tp, entry, mapping, len, - base_flags, (i == last)); + base_flags, (i == last) | (mss << 1)); entry = NEXT_TX(entry); } @@ -2310,7 +2441,7 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev) if (tigon3_4gb_hwbug_workaround(tp, skb, entry, len, last_plus_one, - &start)) + &start, mss)) goto out_unlock; entry = start; @@ -2323,12 +2454,27 @@ static int tg3_start_xmit_4gbug(struct sk_buff *skb, struct net_device *dev) if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) tw32_mailbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); + if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + tr32(MAILBOX_SNDHOST_PROD_IDX_0 + + TG3_64BIT_REG_LOW); } else { + /* First, make sure tg3 sees last descriptor fully + * in SRAM. + */ + if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + tr32(MAILBOX_SNDNIC_PROD_IDX_0 + + TG3_64BIT_REG_LOW); + tw32_mailbox((MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); if (tp->tg3_flags & TG3_FLAG_TXD_MBOX_HWBUG) tw32_mailbox((MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); + + /* Now post the mailbox write itself. */ + if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + tr32(MAILBOX_SNDNIC_PROD_IDX_0 + + TG3_64BIT_REG_LOW); } tp->tx_prod = entry; @@ -2347,7 +2493,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) { struct tg3 *tp = dev->priv; dma_addr_t mapping; - u32 len, entry, base_flags; + u32 len, entry, base_flags, mss; len = (skb->len - skb->data_len); @@ -2370,6 +2516,13 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) base_flags = 0; if (skb->ip_summed == CHECKSUM_HW) base_flags |= TXD_FLAG_TCPUDP_CSUM; +#if TG3_DO_TSO != 0 + if ((mss = skb_shinfo(skb)->tso_size) != 0) + base_flags |= (TXD_FLAG_CPU_PRE_DMA | + TXD_FLAG_CPU_POST_DMA); +#else + mss = 0; +#endif #if TG3_VLAN_TAG_USED if (tp->vlgrp != NULL && vlan_tx_tag_present(skb)) base_flags |= (TXD_FLAG_VLAN | @@ -2383,7 +2536,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping); tg3_set_txd(tp, entry, mapping, len, base_flags, - (skb_shinfo(skb)->nr_frags == 0)); + (skb_shinfo(skb)->nr_frags == 0) | (mss << 1)); entry = NEXT_TX(entry); @@ -2406,7 +2559,7 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) pci_unmap_addr_set(&tp->tx_buffers[entry], mapping, mapping); tg3_set_txd(tp, entry, mapping, len, - base_flags, (i == last)); + base_flags, (i == last) | (mss << 1)); entry = NEXT_TX(entry); } @@ -2420,9 +2573,24 @@ static int tg3_start_xmit(struct sk_buff *skb, struct net_device *dev) if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { tw32_mailbox((MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); + if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + tr32(MAILBOX_SNDHOST_PROD_IDX_0 + + TG3_64BIT_REG_LOW); } else { + /* First, make sure tg3 sees last descriptor fully + * in SRAM. + */ + if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + tr32(MAILBOX_SNDNIC_PROD_IDX_0 + + TG3_64BIT_REG_LOW); + tw32_mailbox((MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW), entry); + + /* Now post the mailbox write itself. */ + if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + tr32(MAILBOX_SNDNIC_PROD_IDX_0 + + TG3_64BIT_REG_LOW); } tp->tx_prod = entry; @@ -2524,7 +2692,7 @@ static void tg3_free_rings(struct tg3 *tp) } for (i = 0; i < TG3_TX_RING_SIZE; ) { - struct ring_info *txp; + struct tx_ring_info *txp; struct sk_buff *skb; int j; @@ -2591,6 +2759,8 @@ static void tg3_init_rings(struct tg3 *tp) writel(0, start); start += 4; } + for (i = 0; i < TG3_TX_RING_SIZE; i++) + tp->tx_buffers[i].prev_vlan_tag = 0; } /* Initialize invariants of the rings, we only set this @@ -2713,12 +2883,13 @@ static void tg3_free_consistent(struct tg3 *tp) */ static int tg3_alloc_consistent(struct tg3 *tp) { - tp->rx_std_buffers = kmalloc(sizeof(struct ring_info) * - (TG3_RX_RING_SIZE + + tp->rx_std_buffers = kmalloc((sizeof(struct ring_info) * + (TG3_RX_RING_SIZE + #if TG3_MINI_RING_WORKS - TG3_RX_MINI_RING_SIZE + + TG3_RX_MINI_RING_SIZE + #endif - TG3_RX_JUMBO_RING_SIZE + + TG3_RX_JUMBO_RING_SIZE)) + + (sizeof(struct tx_ring_info) * TG3_TX_RING_SIZE), GFP_KERNEL); if (!tp->rx_std_buffers) @@ -2729,14 +2900,16 @@ static int tg3_alloc_consistent(struct tg3 *tp) (sizeof(struct ring_info) * (TG3_RX_RING_SIZE + TG3_RX_MINI_RING_SIZE + - TG3_RX_JUMBO_RING_SIZE + - TG3_TX_RING_SIZE))); + TG3_RX_JUMBO_RING_SIZE)) + + (sizeof(struct tx_ring_info) * + TG3_TX_RING_SIZE)); #else memset(tp->rx_std_buffers, 0, (sizeof(struct ring_info) * (TG3_RX_RING_SIZE + - TG3_RX_JUMBO_RING_SIZE + - TG3_TX_RING_SIZE))); + TG3_RX_JUMBO_RING_SIZE)) + + (sizeof(struct tx_ring_info) * + TG3_TX_RING_SIZE)); #endif #if TG3_MINI_RING_WORKS @@ -2745,7 +2918,8 @@ static int tg3_alloc_consistent(struct tg3 *tp) #else tp->rx_jumbo_buffers = &tp->rx_std_buffers[TG3_RX_RING_SIZE]; #endif - tp->tx_buffers = &tp->rx_jumbo_buffers[TG3_RX_JUMBO_RING_SIZE]; + tp->tx_buffers = (struct tx_ring_info *) + &tp->rx_jumbo_buffers[TG3_RX_JUMBO_RING_SIZE]; tp->rx_std = pci_alloc_consistent(tp->pdev, TG3_RX_RING_BYTES, &tp->rx_std_mapping); @@ -2816,13 +2990,13 @@ static int tg3_stop_block(struct tg3 *tp, unsigned long ofs, u32 enable_bit) val = tr32(ofs); val &= ~enable_bit; tw32(ofs, val); + tr32(ofs); for (i = 0; i < MAX_WAIT_CNT; i++) { + udelay(100); val = tr32(ofs); - if ((val & enable_bit) == 0) break; - udelay(100); } if (i == MAX_WAIT_CNT) { @@ -2844,6 +3018,8 @@ static int tg3_abort_hw(struct tg3 *tp) tp->rx_mode &= ~RX_MODE_ENABLE; tw32(MAC_RX_MODE, tp->rx_mode); + tr32(MAC_RX_MODE); + udelay(10); err = tg3_stop_block(tp, RCVBDI_MODE, RCVBDI_MODE_ENABLE); err |= tg3_stop_block(tp, RCVLPC_MODE, RCVLPC_MODE_ENABLE); @@ -2863,9 +3039,13 @@ static int tg3_abort_hw(struct tg3 *tp) tp->mac_mode &= ~MAC_MODE_TDE_ENABLE; tw32(MAC_MODE, tp->mac_mode); + tr32(MAC_MODE); + udelay(40); tp->tx_mode &= ~TX_MODE_ENABLE; tw32(MAC_TX_MODE, tp->tx_mode); + tr32(MAC_TX_MODE); + for (i = 0; i < MAX_WAIT_CNT; i++) { udelay(100); if (!(tr32(MAC_TX_MODE) & TX_MODE_ENABLE)) @@ -2917,6 +3097,14 @@ static void tg3_chip_reset(struct tg3 *tp) } tw32(GRC_MISC_CFG, GRC_MISC_CFG_CORECLK_RESET); + + /* Flush PCI posted writes. The normal MMIO registers + * are inaccessible at this time so this is the only + * way to make this reliably. I tried to use indirect + * register read/write but this upset some 5701 variants. + */ + pci_read_config_dword(tp->pdev, PCI_COMMAND, &val); + udelay(40); udelay(40); udelay(40); @@ -2926,9 +3114,11 @@ static void tg3_chip_reset(struct tg3 *tp) tp->misc_host_ctrl); /* Set MAX PCI retry to zero. */ - pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, - (PCISTATE_ROM_ENABLE | - PCISTATE_ROM_RETRY_ENABLE)); + val = (PCISTATE_ROM_ENABLE | PCISTATE_ROM_RETRY_ENABLE); + if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 && + (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) + val |= PCISTATE_RETRY_SAME_DMA; + pci_write_config_dword(tp->pdev, TG3PCI_PCISTATE, val); pci_restore_state(tp->pdev, tp->pci_cfg_state); @@ -2943,11 +3133,33 @@ static void tg3_chip_reset(struct tg3 *tp) } /* tp->lock is held. */ +static void tg3_stop_fw(struct tg3 *tp) +{ + if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { + u32 val; + int i; + + tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_PAUSE_FW); + val = tr32(GRC_RX_CPU_EVENT); + val |= (1 << 14); + tw32(GRC_RX_CPU_EVENT, val); + + /* Wait for RX cpu to ACK the event. */ + for (i = 0; i < 100; i++) { + if (!(tr32(GRC_RX_CPU_EVENT) & (1 << 14))) + break; + udelay(1); + } + } +} + +/* tp->lock is held. */ static int tg3_halt(struct tg3 *tp) { u32 val; int i; + tg3_stop_fw(tp); tg3_abort_hw(tp); tg3_chip_reset(tp); tg3_write_mem(tp, @@ -2967,6 +3179,17 @@ static int tg3_halt(struct tg3 *tp) return -ENODEV; } + if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { + if (tp->tg3_flags & TG3_FLAG_WOL_ENABLE) + tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX, + DRV_STATE_WOL); + else + tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX, + DRV_STATE_UNLOAD); + } else + tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX, + DRV_STATE_SUSPEND); + return 0; } @@ -2985,7 +3208,7 @@ static int tg3_halt(struct tg3 *tp) #define TG3_FW_BSS_ADDR 0x08000a70 #define TG3_FW_BSS_LEN 0x10 -static u32 t3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = { +static u32 tg3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = { 0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c1d0800, 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100000, 0x0e000018, 0x00000000, 0x0000000d, 0x3c1d0800, 0x37bd3ffc, 0x03a0f021, 0x3c100800, 0x26100034, @@ -3079,7 +3302,7 @@ static u32 t3FwText[(TG3_FW_TEXT_LEN / sizeof(u32)) + 1] = { 0x27bd0008, 0x03e00008, 0x00000000, 0x00000000, 0x00000000 }; -static u32 t3FwRodata[(TG3_FW_RODATA_LEN / sizeof(u32)) + 1] = { +static u32 tg3FwRodata[(TG3_FW_RODATA_LEN / sizeof(u32)) + 1] = { 0x35373031, 0x726c7341, 0x00000000, 0x00000000, 0x53774576, 0x656e7430, 0x00000000, 0x726c7045, 0x76656e74, 0x31000000, 0x556e6b6e, 0x45766e74, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x66617461, 0x6c457272, @@ -3088,7 +3311,7 @@ static u32 t3FwRodata[(TG3_FW_RODATA_LEN / sizeof(u32)) + 1] = { }; #if 0 /* All zeros, dont eat up space with it. */ -u32 t3FwData[(TG3_FW_DATA_LEN / sizeof(u32)) + 1] = { +u32 tg3FwData[(TG3_FW_DATA_LEN / sizeof(u32)) + 1] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; @@ -3112,6 +3335,7 @@ static int tg3_reset_cpu(struct tg3 *tp, u32 offset) break; tw32(offset + CPU_STATE, 0xffffffff); tw32(offset + CPU_MODE, CPU_MODE_RESET); + tr32(offset + CPU_MODE); udelay(10); } else { for (i = 0; i < 10000; i++) { @@ -3119,6 +3343,7 @@ static int tg3_reset_cpu(struct tg3 *tp, u32 offset) break; tw32(offset + CPU_STATE, 0xffffffff); tw32(offset + CPU_MODE, CPU_MODE_RESET); + tr32(offset + CPU_MODE); udelay(10); } } @@ -3133,51 +3358,89 @@ static int tg3_reset_cpu(struct tg3 *tp, u32 offset) return 0; } +struct fw_info { + unsigned int text_base; + unsigned int text_len; + u32 *text_data; + unsigned int rodata_base; + unsigned int rodata_len; + u32 *rodata_data; + unsigned int data_base; + unsigned int data_len; + u32 *data_data; +}; + /* tp->lock is held. */ static int tg3_load_firmware_cpu(struct tg3 *tp, u32 cpu_base, u32 cpu_scratch_base, - int cpu_scratch_size) + int cpu_scratch_size, struct fw_info *info) { int err, i; + u32 orig_tg3_flags = tp->tg3_flags; + + /* Force use of PCI config space for indirect register + * write calls. + */ + tp->tg3_flags |= TG3_FLAG_PCIX_TARGET_HWBUG; err = tg3_reset_cpu(tp, cpu_base); if (err) - return err; + goto out; for (i = 0; i < cpu_scratch_size; i += sizeof(u32)) tg3_write_indirect_reg32(tp, cpu_scratch_base + i, 0); tw32(cpu_base + CPU_STATE, 0xffffffff); tw32(cpu_base + CPU_MODE, tr32(cpu_base+CPU_MODE)|CPU_MODE_HALT); - for (i = 0; i < (TG3_FW_TEXT_LEN / sizeof(u32)); i++) + for (i = 0; i < (info->text_len / sizeof(u32)); i++) tg3_write_indirect_reg32(tp, (cpu_scratch_base + - (TG3_FW_TEXT_ADDR & 0xffff) + + (info->text_base & 0xffff) + (i * sizeof(u32))), - t3FwText[i]); - for (i = 0; i < (TG3_FW_RODATA_LEN / sizeof(u32)); i++) + (info->text_data ? + info->text_data[i] : 0)); + for (i = 0; i < (info->rodata_len / sizeof(u32)); i++) tg3_write_indirect_reg32(tp, (cpu_scratch_base + - (TG3_FW_RODATA_ADDR & 0xffff) + + (info->rodata_base & 0xffff) + (i * sizeof(u32))), - t3FwRodata[i]); - for (i = 0; i < (TG3_FW_DATA_LEN / sizeof(u32)); i++) + (info->rodata_data ? + info->rodata_data[i] : 0)); + for (i = 0; i < (info->data_len / sizeof(u32)); i++) tg3_write_indirect_reg32(tp, (cpu_scratch_base + - (TG3_FW_DATA_ADDR & 0xffff) + + (info->data_base & 0xffff) + (i * sizeof(u32))), - 0); + (info->data_data ? + info->data_data[i] : 0)); - return 0; + err = 0; + +out: + tp->tg3_flags = orig_tg3_flags; + return err; } /* tp->lock is held. */ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp) { + struct fw_info info; int err, i; + info.text_base = TG3_FW_TEXT_ADDR; + info.text_len = TG3_FW_TEXT_LEN; + info.text_data = &tg3FwText[0]; + info.rodata_base = TG3_FW_RODATA_ADDR; + info.rodata_len = TG3_FW_RODATA_LEN; + info.rodata_data = &tg3FwRodata[0]; + info.data_base = TG3_FW_DATA_ADDR; + info.data_len = TG3_FW_DATA_LEN; + info.data_data = NULL; + err = tg3_load_firmware_cpu(tp, RX_CPU_BASE, - RX_CPU_SCRATCH_BASE, RX_CPU_SCRATCH_SIZE); + RX_CPU_SCRATCH_BASE, RX_CPU_SCRATCH_SIZE, + &info); if (err) return err; err = tg3_load_firmware_cpu(tp, TX_CPU_BASE, - TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE); + TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE, + &info); if (err) return err; @@ -3215,6 +3478,336 @@ static int tg3_load_5701_a0_firmware_fix(struct tg3 *tp) return 0; } +#if TG3_DO_TSO != 0 + +#define TG3_TSO_FW_RELEASE_MAJOR 0x1 +#define TG3_TSO_FW_RELASE_MINOR 0x8 +#define TG3_TSO_FW_RELEASE_FIX 0x0 +#define TG3_TSO_FW_START_ADDR 0x08000000 +#define TG3_TSO_FW_TEXT_ADDR 0x08000000 +#define TG3_TSO_FW_TEXT_LEN 0x1650 +#define TG3_TSO_FW_RODATA_ADDR 0x08001650 +#define TG3_TSO_FW_RODATA_LEN 0x30 +#define TG3_TSO_FW_DATA_ADDR 0x080016a0 +#define TG3_TSO_FW_DATA_LEN 0x20 +#define TG3_TSO_FW_SBSS_ADDR 0x080016c0 +#define TG3_TSO_FW_SBSS_LEN 0x14 +#define TG3_TSO_FW_BSS_ADDR 0x080016e0 +#define TG3_TSO_FW_BSS_LEN 0x8fc + +static u32 tg3TsoFwText[] = { + 0x00000000, 0x10000003, 0x00000000, 0x0000000d, 0x0000000d, 0x3c1d0800, + 0x37bd4000, 0x03a0f021, 0x3c100800, 0x26100000, 0x0e000010, 0x00000000, + 0x0000000d, 0x00000000, 0x00000000, 0x00000000, 0x27bdffe0, 0x3c1bc000, + 0xafbf0018, 0x0e000058, 0xaf60680c, 0x3c040800, 0x24841650, 0x03602821, + 0x24060001, 0x24070004, 0xafa00010, 0x0e00006c, 0xafa00014, 0x8f625c50, + 0x34420001, 0xaf625c50, 0x8f625c90, 0x34420001, 0xaf625c90, 0x2402ffff, + 0x0e000098, 0xaf625404, 0x8fbf0018, 0x03e00008, 0x27bd0020, 0x00000000, + 0x00000000, 0x00000000, 0x24030b60, 0x24050fff, 0xac000b50, 0x00002021, + 0xac640000, 0x24630004, 0x0065102b, 0x1440fffc, 0x24840001, 0x24030b60, + 0x0065102b, 0x10400011, 0x00002021, 0x24090b54, 0x3c06dead, 0x34c6beef, + 0x24080b58, 0x24070b5c, 0x8c620000, 0x50440006, 0x24630004, 0xad260000, + 0x8c620000, 0xace40000, 0xad020000, 0x24630004, 0x0065102b, 0x1440fff6, + 0x24840001, 0x03e00008, 0x00000000, 0x27bdfff8, 0x18800009, 0x00002821, + 0x8f63680c, 0x8f62680c, 0x1043fffe, 0x00000000, 0x24a50001, 0x00a4102a, + 0x1440fff9, 0x00000000, 0x03e00008, 0x27bd0008, 0x3c020800, 0x34423000, + 0x3c030800, 0x34633000, 0x3c040800, 0x348437ff, 0x3c010800, 0xac2216c4, + 0x24020040, 0x3c010800, 0xac2216c8, 0x3c010800, 0xac2016c0, 0xac600000, + 0x24630004, 0x0083102b, 0x5040fffd, 0xac600000, 0x03e00008, 0x00000000, + 0x00804821, 0x8faa0010, 0x3c020800, 0x8c4216c0, 0x3c040800, 0x8c8416c8, + 0x8fab0014, 0x24430001, 0x0044102b, 0x3c010800, 0xac2316c0, 0x14400003, + 0x00004021, 0x3c010800, 0xac2016c0, 0x3c020800, 0x8c4216c0, 0x3c030800, + 0x8c6316c4, 0x91240000, 0x00021140, 0x00431021, 0x00481021, 0x25080001, + 0xa0440000, 0x29020008, 0x1440fff4, 0x25290001, 0x3c020800, 0x8c4216c0, + 0x3c030800, 0x8c6316c4, 0x8f64680c, 0x00021140, 0x00431021, 0xac440008, + 0xac45000c, 0xac460010, 0xac470014, 0xac4a0018, 0x03e00008, 0xac4b001c, + 0x00000000, 0x00000000, 0x27bdffe0, 0xafbf0018, 0xafb10014, 0x0e0000b6, + 0xafb00010, 0x24110001, 0x8f706820, 0x32020100, 0x10400003, 0x00000000, + 0x0e000127, 0x00000000, 0x8f706820, 0x32022000, 0x10400004, 0x32020001, + 0x0e00025a, 0x24040001, 0x32020001, 0x10400003, 0x00000000, 0x0e0000e6, + 0x00000000, 0x0a00009e, 0xaf715028, 0x8fbf0018, 0x8fb10014, 0x8fb00010, + 0x03e00008, 0x27bd0020, 0x27bdffe0, 0x3c040800, 0x24841660, 0x00002821, + 0x00003021, 0x00003821, 0xafbf0018, 0xafa00010, 0x0e00006c, 0xafa00014, + 0x3c010800, 0xa4201fb8, 0x3c010800, 0xa02016f8, 0x3c010800, 0xac2016fc, + 0x3c010800, 0xac201700, 0x3c010800, 0xac201704, 0x3c010800, 0xac20170c, + 0x3c010800, 0xac201718, 0x3c010800, 0xac20171c, 0x8f624434, 0x3c010800, + 0xac2216e8, 0x8f624438, 0x3c010800, 0xac2216ec, 0x8f624410, 0x3c010800, + 0xac2016e0, 0x3c010800, 0xac2016e4, 0x3c010800, 0xac201fc0, 0x3c010800, + 0xac201f68, 0x3c010800, 0xac201f6c, 0x3c010800, 0xac2216f0, 0x8fbf0018, + 0x03e00008, 0x27bd0020, 0x27bdffe0, 0x3c040800, 0x2484166c, 0x00002821, + 0x00003021, 0x00003821, 0xafbf0018, 0xafa00010, 0x0e00006c, 0xafa00014, + 0x3c040800, 0x24841660, 0x00002821, 0x00003021, 0x00003821, 0xafa00010, + 0x0e00006c, 0xafa00014, 0x3c010800, 0xa4201fb8, 0x3c010800, 0xa02016f8, + 0x3c010800, 0xac2016fc, 0x3c010800, 0xac201700, 0x3c010800, 0xac201704, + 0x3c010800, 0xac20170c, 0x3c010800, 0xac201718, 0x3c010800, 0xac20171c, + 0x8f624434, 0x3c010800, 0xac2216e8, 0x8f624438, 0x3c010800, 0xac2216ec, + 0x8f624410, 0x3c010800, 0xac2016e0, 0x3c010800, 0xac2016e4, 0x3c010800, + 0xac201fc0, 0x3c010800, 0xac201f68, 0x3c010800, 0xac201f6c, 0x3c010800, + 0xac2216f0, 0x0e000120, 0x00002021, 0x8fbf0018, 0x03e00008, 0x27bd0020, + 0x24020001, 0x8f636820, 0x00821004, 0x00021027, 0x00621824, 0x03e00008, + 0xaf636820, 0x27bdffd0, 0x3c0300ff, 0xafbf002c, 0xafb60028, 0xafb50024, + 0xafb40020, 0xafb3001c, 0xafb20018, 0xafb10014, 0xafb00010, 0x8f665c5c, + 0x3c040800, 0x2484171c, 0x8c820000, 0x3463fff8, 0x14460005, 0x00c38824, + 0x3c020800, 0x904216f8, 0x14400115, 0x00000000, 0x00111902, 0x306300ff, + 0x30c20003, 0x000211c0, 0x00623825, 0x00e02821, 0x00061602, 0xac860000, + 0x3c030800, 0x906316f8, 0x3044000f, 0x1460002b, 0x00804021, 0x24020001, + 0x3c010800, 0xa02216f8, 0x00071100, 0x00821025, 0x3c010800, 0xac2016fc, + 0x3c010800, 0xac201700, 0x3c010800, 0xac201704, 0x3c010800, 0xac20170c, + 0x3c010800, 0xac201718, 0x3c010800, 0xac201710, 0x3c010800, 0xac201714, + 0x3c010800, 0xa4221fb8, 0x9623000c, 0x30628000, 0x10400008, 0x30627fff, + 0x2442003e, 0x3c010800, 0xa42216f6, 0x24020001, 0x3c010800, 0x0a00016e, + 0xac221fd4, 0x24620036, 0x3c010800, 0xa42216f6, 0x3c010800, 0xac201fd4, + 0x3c010800, 0xac201fd0, 0x3c010800, 0x0a000176, 0xac201fd8, 0x9622000c, + 0x3c010800, 0xa4221fcc, 0x3c040800, 0x248416fc, 0x8c820000, 0x00021100, + 0x3c010800, 0x00220821, 0xac311728, 0x8c820000, 0x00021100, 0x3c010800, + 0x00220821, 0xac26172c, 0x8c820000, 0x24a30001, 0x306701ff, 0x00021100, + 0x3c010800, 0x00220821, 0xac271730, 0x8c820000, 0x00021100, 0x3c010800, + 0x00220821, 0xac281734, 0x96230008, 0x3c020800, 0x8c42170c, 0x00432821, + 0x3c010800, 0xac25170c, 0x9622000a, 0x30420004, 0x14400019, 0x00071100, + 0x3c02c000, 0x00c21825, 0xaf635c5c, 0x8f625c50, 0x30420002, 0x1440fffc, + 0x00000000, 0x8f630c14, 0x3063000f, 0x2c620002, 0x1440001e, 0x00000000, + 0x8f630c14, 0x3c020800, 0x8c4216b4, 0x3063000f, 0x24420001, 0x3c010800, + 0xac2216b4, 0x2c620002, 0x1040fff7, 0x00000000, 0x0a0001c1, 0x00000000, + 0x3c030800, 0x8c6316e0, 0x3c040800, 0x948416f4, 0x01021025, 0x3c010800, + 0xa4221fba, 0x24020001, 0x3c010800, 0xac221718, 0x24630001, 0x0085202a, + 0x3c010800, 0x10800003, 0xac2316e0, 0x3c010800, 0xa42516f4, 0x3c030800, + 0x246316fc, 0x8c620000, 0x24420001, 0xac620000, 0x28420080, 0x14400005, + 0x24020001, 0x0e0002df, 0x24040002, 0x0a000250, 0x00000000, 0x3c030800, + 0x906316f8, 0x1462007c, 0x24020003, 0x3c160800, 0x96d616f6, 0x3c050800, + 0x8ca5170c, 0x32c4ffff, 0x00a4102a, 0x14400078, 0x00000000, 0x3c020800, + 0x8c421718, 0x10400005, 0x32c2ffff, 0x14a40003, 0x00000000, 0x3c010800, + 0xac231fd0, 0x10400062, 0x00009021, 0x0040a021, 0x3c150800, 0x26b51700, + 0x26b30010, 0x8ea20000, 0x00028100, 0x3c110800, 0x02308821, 0x0e0002e1, + 0x8e311728, 0x00403021, 0x10c00059, 0x00000000, 0x9628000a, 0x31020040, + 0x10400004, 0x2407180c, 0x8e22000c, 0x2407188c, 0xacc20018, 0x31021000, + 0x10400004, 0x34e32000, 0x00081040, 0x3042c000, 0x00623825, 0x3c030800, + 0x00701821, 0x8c631730, 0x3c020800, 0x00501021, 0x8c421734, 0x00031d00, + 0x00021400, 0x00621825, 0xacc30014, 0x8ea30004, 0x96220008, 0x00432023, + 0x3242ffff, 0x3083ffff, 0x00431021, 0x0282102a, 0x14400002, 0x02d22823, + 0x00802821, 0x8e620000, 0x30a4ffff, 0x00441021, 0xae620000, 0x8e220000, + 0xacc20000, 0x8e220004, 0x8e63fff4, 0x00431021, 0xacc20004, 0xa4c5000e, + 0x8e62fff4, 0x00441021, 0xae62fff4, 0x96230008, 0x0043102a, 0x14400005, + 0x02459021, 0x8e62fff0, 0xae60fff4, 0x24420001, 0xae62fff0, 0xacc00008, + 0x3242ffff, 0x14540008, 0x24020305, 0x31020080, 0x54400001, 0x34e70010, + 0x24020905, 0xa4c2000c, 0x0a000233, 0x34e70020, 0xa4c2000c, 0x30e2ffff, + 0xacc20010, 0x3c020800, 0x8c421fd0, 0x10400003, 0x3c024b65, 0x0a00023d, + 0x34427654, 0x3c02b49a, 0x344289ab, 0xacc2001c, 0x0e000560, 0x00c02021, + 0x3242ffff, 0x0054102b, 0x1440ffa4, 0x00000000, 0x24020002, 0x3c010800, + 0x0a000250, 0xa02216f8, 0x8ea208bc, 0x24420001, 0x0a000250, 0xaea208bc, + 0x14620003, 0x00000000, 0x0e000450, 0x00000000, 0x8fbf002c, 0x8fb60028, + 0x8fb50024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, + 0x03e00008, 0x27bd0030, 0x27bdffd8, 0xafb3001c, 0x00809821, 0xafbf0020, + 0xafb20018, 0xafb10014, 0xafb00010, 0x8f725c9c, 0x3c0200ff, 0x3442fff8, + 0x3c040800, 0x24841714, 0x02428824, 0x9623000e, 0x8c820000, 0x00431021, + 0xac820000, 0x8e220010, 0x30420020, 0x14400011, 0x00000000, 0x0e0002f7, + 0x02202021, 0x3c02c000, 0x02421825, 0xaf635c9c, 0x8f625c90, 0x30420002, + 0x10400061, 0x00000000, 0xaf635c9c, 0x8f625c90, 0x30420002, 0x1040005c, + 0x00000000, 0x0a000278, 0x00000000, 0x8e220008, 0x00021c02, 0x000321c0, + 0x3042ffff, 0x3c030800, 0x906316f8, 0x000229c0, 0x24020002, 0x14620003, + 0x3c034b65, 0x0a000290, 0x00008021, 0x8e22001c, 0x34637654, 0x10430002, + 0x24100002, 0x24100001, 0x0e000300, 0x02003021, 0x24020003, 0x3c010800, + 0xa02216f8, 0x24020002, 0x1202000a, 0x24020001, 0x3c030800, 0x8c631fd0, + 0x10620006, 0x00000000, 0x3c020800, 0x94421fb8, 0x00021400, 0x0a0002cd, + 0xae220014, 0x3c040800, 0x24841fba, 0x94820000, 0x00021400, 0xae220014, + 0x3c020800, 0x8c42171c, 0x3c03c000, 0x3c010800, 0xa02016f8, 0x00431025, + 0xaf625c5c, 0x8f625c50, 0x30420002, 0x10400009, 0x00000000, 0x2484f762, + 0x8c820000, 0x00431025, 0xaf625c5c, 0x8f625c50, 0x30420002, 0x1440fffa, + 0x00000000, 0x3c020800, 0x244216e4, 0x8c430000, 0x24630001, 0xac430000, + 0x8f630c14, 0x3063000f, 0x2c620002, 0x1440000b, 0x00009821, 0x8f630c14, + 0x3c020800, 0x8c4216b4, 0x3063000f, 0x24420001, 0x3c010800, 0xac2216b4, + 0x2c620002, 0x1040fff7, 0x00009821, 0x3c024000, 0x02421825, 0xaf635c9c, + 0x8f625c90, 0x30420002, 0x1440fffc, 0x00000000, 0x12600003, 0x00000000, + 0x0e000450, 0x00000000, 0x8fbf0020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, + 0x8fb00010, 0x03e00008, 0x27bd0028, 0x0a0002df, 0x00000000, 0x8f634450, + 0x3c040800, 0x248416e8, 0x8c820000, 0x00031c02, 0x0043102b, 0x14400007, + 0x3c038000, 0x8c840004, 0x8f624450, 0x00021c02, 0x0083102b, 0x1040fffc, + 0x3c038000, 0xaf634444, 0x8f624444, 0x00431024, 0x1440fffd, 0x00000000, + 0x8f624448, 0x03e00008, 0x3042ffff, 0x3c024000, 0x00822025, 0xaf645c38, + 0x8f625c30, 0x30420002, 0x1440fffc, 0x00000000, 0x03e00008, 0x00000000, + 0x27bdffe0, 0x00805021, 0x14c00017, 0x254c0008, 0x3c020800, 0x8c421fd4, + 0x1040000a, 0x2402003e, 0x3c010800, 0xa4221fb0, 0x24020016, 0x3c010800, + 0xa4221fb2, 0x2402002a, 0x3c010800, 0x0a00031a, 0xa4221fb4, 0x95420014, + 0x3c010800, 0xa4221fb0, 0x8d430010, 0x00031402, 0x3c010800, 0xa4221fb2, + 0x3c010800, 0xa4231fb4, 0x3c040800, 0x94841fb4, 0x3c030800, 0x94631fb2, + 0x958d0006, 0x3c020800, 0x94421fb0, 0x00832023, 0x01a27023, 0x3065ffff, + 0x24a20028, 0x01824021, 0x3082ffff, 0x14c0001a, 0x01025821, 0x9562000c, + 0x3042003f, 0x3c010800, 0xa4221fb6, 0x95620004, 0x95630006, 0x3c010800, + 0xac201fc4, 0x3c010800, 0xac201fc8, 0x00021400, 0x00431025, 0x3c010800, + 0xac221720, 0x95020004, 0x3c010800, 0xa4221724, 0x95030002, 0x01a51023, + 0x0043102a, 0x10400010, 0x24020001, 0x3c010800, 0x0a00034e, 0xac221fd8, + 0x3c030800, 0x8c631fc8, 0x3c020800, 0x94421724, 0x00431021, 0xa5020004, + 0x3c020800, 0x94421720, 0xa5620004, 0x3c020800, 0x8c421720, 0xa5620006, + 0x3c020800, 0x8c421fd0, 0x3c070800, 0x8ce71fc4, 0x3c050800, 0x144000c7, + 0x8ca51fc8, 0x3c020800, 0x94421724, 0x00451821, 0x3063ffff, 0x0062182b, + 0x24020002, 0x10c2000d, 0x00a32823, 0x3c020800, 0x94421fb6, 0x30420009, + 0x10400008, 0x00000000, 0x9562000c, 0x3042fff6, 0xa562000c, 0x3c020800, + 0x94421fb6, 0x30420009, 0x00e23823, 0x3c020800, 0x8c421fd8, 0x1040004b, + 0x24020002, 0x01003021, 0x3c020800, 0x94421fb2, 0x00003821, 0xa500000a, + 0x01a21023, 0xa5020002, 0x3082ffff, 0x00021042, 0x18400008, 0x00002821, + 0x00401821, 0x94c20000, 0x24e70001, 0x00a22821, 0x00e3102a, 0x1440fffb, + 0x24c60002, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402, 0x00a22821, + 0x00a04821, 0x00051027, 0xa502000a, 0x00002821, 0x2506000c, 0x00003821, + 0x94c20000, 0x24e70001, 0x00a22821, 0x2ce20004, 0x1440fffb, 0x24c60002, + 0x95020002, 0x00003821, 0x91030009, 0x00442023, 0x01603021, 0x3082ffff, + 0xa4c00010, 0x00621821, 0x00021042, 0x18400010, 0x00a32821, 0x00404021, + 0x94c20000, 0x24c60002, 0x00a22821, 0x30c2007f, 0x14400006, 0x24e70001, + 0x8d430000, 0x3c02007f, 0x3442ff80, 0x00625024, 0x25460008, 0x00e8102a, + 0x1440fff3, 0x00000000, 0x30820001, 0x10400005, 0x00051c02, 0xa0c00001, + 0x94c20000, 0x00a22821, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402, + 0x00a22821, 0x0a000415, 0x30a5ffff, 0x14c20063, 0x00000000, 0x3c090800, + 0x95291fb2, 0x95030002, 0x01a91023, 0x1062005d, 0x01003021, 0x00003821, + 0x00002821, 0x01a91023, 0xa5020002, 0x3082ffff, 0x00021042, 0x18400008, + 0xa500000a, 0x00401821, 0x94c20000, 0x24e70001, 0x00a22821, 0x00e3102a, + 0x1440fffb, 0x24c60002, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402, + 0x00a22821, 0x00a04821, 0x00051027, 0xa502000a, 0x00002821, 0x2506000c, + 0x00003821, 0x94c20000, 0x24e70001, 0x00a22821, 0x2ce20004, 0x1440fffb, + 0x24c60002, 0x95020002, 0x00003821, 0x91030009, 0x00442023, 0x01603021, + 0x3082ffff, 0xa4c00010, 0x3c040800, 0x94841fb4, 0x00621821, 0x00a32821, + 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051c02, 0x3c020800, 0x94421fb0, + 0x00a34021, 0x00441023, 0x00021fc2, 0x00431021, 0x00021043, 0x18400010, + 0x00002821, 0x00402021, 0x94c20000, 0x24c60002, 0x00a22821, 0x30c2007f, + 0x14400006, 0x24e70001, 0x8d430000, 0x3c02007f, 0x3442ff80, 0x00625024, + 0x25460008, 0x00e4102a, 0x1440fff3, 0x00000000, 0x3c020800, 0x94421fcc, + 0x00a22821, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402, 0x00a22821, + 0x3102ffff, 0x00a22821, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402, + 0x00a22821, 0x00a02021, 0x00051027, 0xa5620010, 0xad800014, 0x0a000435, + 0xad800000, 0x8d830010, 0x00602021, 0x10a00007, 0x00034c02, 0x01252821, + 0x00051402, 0x30a3ffff, 0x00432821, 0x00051402, 0x00a24821, 0x00091027, + 0xa502000a, 0x3c030800, 0x94631fb4, 0x3082ffff, 0x01a21021, 0x00432823, + 0x00a72821, 0x00051c02, 0x30a2ffff, 0x00622821, 0x00051402, 0x00a22821, + 0x00a02021, 0x00051027, 0xa5620010, 0x3082ffff, 0x00091c00, 0x00431025, + 0xad820010, 0x3c020800, 0x8c421fd4, 0x10400002, 0x25a2fff2, 0xa5820034, + 0x3c020800, 0x8c421fc8, 0x3c030800, 0x8c631720, 0x24420001, 0x3c010800, + 0xac221fc8, 0x3c020800, 0x8c421fc4, 0x31c4ffff, 0x00641821, 0x3c010800, + 0xac231720, 0x00441021, 0x3c010800, 0xac221fc4, 0x03e00008, 0x27bd0020, + 0x27bdffc8, 0x3c040800, 0x248416f8, 0xafbf0034, 0xafbe0030, 0xafb7002c, + 0xafb60028, 0xafb50024, 0xafb40020, 0xafb3001c, 0xafb20018, 0xafb10014, + 0xafb00010, 0x90830000, 0x24020003, 0x146200f4, 0x00000000, 0x3c020800, + 0x8c421710, 0x3c030800, 0x8c63170c, 0x3c1e0800, 0x97de16f6, 0x0043102a, + 0x104000eb, 0x3c168000, 0x249708c4, 0x33d5ffff, 0x24920018, 0x3c020800, + 0x8c421718, 0x104000e4, 0x00000000, 0x3c140800, 0x96941fb0, 0x3282ffff, + 0x104000d6, 0x00008021, 0x00409821, 0x00008821, 0x8f634450, 0x3c020800, + 0x8c4216e8, 0x00031c02, 0x0043102b, 0x14400008, 0x00000000, 0x3c040800, + 0x8c8416ec, 0x8f624450, 0x00021c02, 0x0083102b, 0x1040fffc, 0x00000000, + 0xaf764444, 0x8f624444, 0x00561024, 0x10400006, 0x00000000, 0x3c038000, + 0x8f624444, 0x00431024, 0x1440fffd, 0x00000000, 0x8f624448, 0x3046ffff, + 0x10c0005f, 0x00000000, 0x3c090800, 0x01314821, 0x8d291728, 0x9528000a, + 0x31020040, 0x10400004, 0x2407180c, 0x8d22000c, 0x2407188c, 0xacc20018, + 0x31021000, 0x10400004, 0x34e32000, 0x00081040, 0x3042c000, 0x00623825, + 0x31020080, 0x54400001, 0x34e70010, 0x3c020800, 0x00511021, 0x8c421730, + 0x3c030800, 0x00711821, 0x8c631734, 0x00021500, 0x00031c00, 0x00431025, + 0xacc20014, 0x95240008, 0x3202ffff, 0x00821021, 0x0262102a, 0x14400002, + 0x02902823, 0x00802821, 0x8d220000, 0x02058021, 0xacc20000, 0x8d220004, + 0x00c02021, 0x26310010, 0xac820004, 0x30e2ffff, 0xac800008, 0xa485000e, + 0xac820010, 0x24020305, 0x0e000560, 0xa482000c, 0x3202ffff, 0x0053102b, + 0x1440ffaf, 0x3202ffff, 0x0a00054c, 0x00000000, 0x8e420000, 0x8e43fffc, + 0x0043102a, 0x10400084, 0x00000000, 0x8e45fff0, 0x8f644450, 0x3c030800, + 0x8c6316e8, 0x00051100, 0x3c090800, 0x01224821, 0x8d291728, 0x00041402, + 0x0062182b, 0x14600008, 0x00000000, 0x3c030800, 0x8c6316ec, 0x8f624450, + 0x00021402, 0x0062102b, 0x1040fffc, 0x00000000, 0xaf764444, 0x8f624444, + 0x00561024, 0x10400006, 0x00000000, 0x3c038000, 0x8f624444, 0x00431024, + 0x1440fffd, 0x00000000, 0x8f624448, 0x3046ffff, 0x14c00005, 0x00000000, + 0x8ee20000, 0x24420001, 0x0a000554, 0xaee20000, 0x9528000a, 0x31020040, + 0x10400004, 0x2407180c, 0x8d22000c, 0x2407188c, 0xacc20018, 0x31021000, + 0x10400004, 0x34e32000, 0x00081040, 0x3042c000, 0x00623825, 0x00051900, + 0x3c020800, 0x00431021, 0x8c421730, 0x3c010800, 0x00230821, 0x8c231734, + 0x00021500, 0x00031c00, 0x00431025, 0xacc20014, 0x3c030800, 0x8c631704, + 0x95220008, 0x00432023, 0x3202ffff, 0x3083ffff, 0x00431021, 0x02a2102a, + 0x14400002, 0x03d02823, 0x00802821, 0x8e420000, 0x30a4ffff, 0x00441021, + 0xae420000, 0xa4c5000e, 0x8d220000, 0xacc20000, 0x8d220004, 0x8e43fff4, + 0x00431021, 0xacc20004, 0x8e43fff4, 0x95220008, 0x00641821, 0x0062102a, + 0x14400006, 0x02058021, 0x8e42fff0, 0xae40fff4, 0x24420001, 0x0a000530, + 0xae42fff0, 0xae43fff4, 0xacc00008, 0x3202ffff, 0x10550003, 0x31020004, + 0x10400006, 0x24020305, 0x31020080, 0x54400001, 0x34e70010, 0x34e70020, + 0x24020905, 0xa4c2000c, 0x30e2ffff, 0xacc20010, 0x3c030800, 0x8c63170c, + 0x3c020800, 0x8c421710, 0x54620004, 0x3c02b49a, 0x3c024b65, 0x0a000548, + 0x34427654, 0x344289ab, 0xacc2001c, 0x0e000560, 0x00c02021, 0x3202ffff, + 0x0055102b, 0x1440ff7e, 0x00000000, 0x8e420000, 0x8e43fffc, 0x0043102a, + 0x1440ff1a, 0x00000000, 0x8fbf0034, 0x8fbe0030, 0x8fb7002c, 0x8fb60028, + 0x8fb50024, 0x8fb40020, 0x8fb3001c, 0x8fb20018, 0x8fb10014, 0x8fb00010, + 0x03e00008, 0x27bd0038, 0x27bdffe8, 0xafbf0014, 0xafb00010, 0x8f624450, + 0x8f634410, 0x0a00056f, 0x00808021, 0x8f626820, 0x30422000, 0x10400003, + 0x00000000, 0x0e00025a, 0x00002021, 0x8f624450, 0x8f634410, 0x3042ffff, + 0x0043102b, 0x1440fff5, 0x00000000, 0x8f630c14, 0x3063000f, 0x2c620002, + 0x1440000b, 0x00000000, 0x8f630c14, 0x3c020800, 0x8c4216b4, 0x3063000f, + 0x24420001, 0x3c010800, 0xac2216b4, 0x2c620002, 0x1040fff7, 0x00000000, + 0xaf705c18, 0x8f625c10, 0x30420002, 0x10400009, 0x00000000, 0x8f626820, + 0x30422000, 0x1040fff8, 0x00000000, 0x0e00025a, 0x00002021, 0x0a000582, + 0x00000000, 0x8fbf0014, 0x8fb00010, 0x03e00008, 0x27bd0018, 0x00000000, + 0x00000000 +}; + +u32 tg3TsoFwRodata[] = { + 0x4d61696e, 0x43707542, 0x00000000, 0x00000000, 0x74637073, 0x6567496e, + 0x00000000, 0x53774576, 0x656e7430, 0x00000000, 0x00000000, 0x00000000, + 0x00000000 +}; + +#if 0 /* All zeros, dont eat up space with it. */ +u32 tg3TsoFwData[] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000 +}; +#endif + +/* tp->lock is held. */ +static int tg3_load_tso_firmware(struct tg3 *tp) +{ + struct fw_info info; + int err, i; + + info.text_base = TG3_TSO_FW_TEXT_ADDR; + info.text_len = TG3_TSO_FW_TEXT_LEN; + info.text_data = &tg3TsoFwText[0]; + info.rodata_base = TG3_TSO_FW_RODATA_ADDR; + info.rodata_len = TG3_TSO_FW_RODATA_LEN; + info.rodata_data = &tg3TsoFwRodata[0]; + info.data_base = TG3_TSO_FW_DATA_ADDR; + info.data_len = TG3_TSO_FW_DATA_LEN; + info.data_data = NULL; + + err = tg3_load_firmware_cpu(tp, TX_CPU_BASE, + TX_CPU_SCRATCH_BASE, TX_CPU_SCRATCH_SIZE, + &info); + if (err) + return err; + + /* Now startup only the TX cpu. */ + tw32(TX_CPU_BASE + CPU_STATE, 0xffffffff); + tw32(TX_CPU_BASE + CPU_PC, TG3_TSO_FW_TEXT_ADDR); + + /* Flush posted writes. */ + tr32(TX_CPU_BASE + CPU_PC); + for (i = 0; i < 5; i++) { + if (tr32(TX_CPU_BASE + CPU_PC) == TG3_TSO_FW_TEXT_ADDR) + break; + tw32(TX_CPU_BASE + CPU_STATE, 0xffffffff); + tw32(TX_CPU_BASE + CPU_MODE, CPU_MODE_HALT); + tw32(TX_CPU_BASE + CPU_PC, TG3_TSO_FW_TEXT_ADDR); + + /* Flush posted writes. */ + tr32(TX_CPU_BASE + CPU_PC); + + udelay(1000); + } + if (i >= 5) { + printk(KERN_ERR PFX "tg3_load_tso_firmware fails for %s " + "to set TX CPU PC, is %08x should be %08x\n", + tp->dev->name, tr32(TX_CPU_BASE + CPU_PC), + TG3_TSO_FW_TEXT_ADDR); + return -ENODEV; + } + tw32(TX_CPU_BASE + CPU_STATE, 0xffffffff); + tw32(TX_CPU_BASE + CPU_MODE, 0x00000000); + + /* Flush posted writes. */ + tr32(TX_CPU_BASE + CPU_MODE); + + return 0; +} + +#endif /* TG3_DO_TSO != 0 */ + /* tp->lock is held. */ static void __tg3_set_mac_addr(struct tg3 *tp) { @@ -3294,6 +3887,8 @@ static int tg3_reset_hw(struct tg3 *tp) tg3_disable_ints(tp); + tg3_stop_fw(tp); + if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE) { err = tg3_abort_hw(tp); if (err) @@ -3311,6 +3906,8 @@ static int tg3_reset_hw(struct tg3 *tp) tw32(MAC_MODE, tp->mac_mode); } else tw32(MAC_MODE, 0); + tr32(MAC_MODE); + udelay(40); /* Wait for firmware initialization to complete. */ for (i = 0; i < 100000; i++) { @@ -3326,6 +3923,13 @@ static int tg3_reset_hw(struct tg3 *tp) return -ENODEV; } + if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) + tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX, + DRV_STATE_START); + else + tg3_write_mem(tp, NIC_SRAM_FW_DRV_STATE_MBOX, + DRV_STATE_SUSPEND); + /* This works around an issue with Athlon chipsets on * B3 tigon3 silicon. This bit has no effect on any * other revision. @@ -3333,6 +3937,14 @@ static int tg3_reset_hw(struct tg3 *tp) val = tr32(TG3PCI_CLOCK_CTRL); val |= CLOCK_CTRL_DELAY_PCI_GRANT; tw32(TG3PCI_CLOCK_CTRL, val); + tr32(TG3PCI_CLOCK_CTRL); + + if (tp->pci_chip_rev_id == CHIPREV_ID_5704_A0 && + (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) { + val = tr32(TG3PCI_PCISTATE); + val |= PCISTATE_RETRY_SAME_DMA; + tw32(TG3PCI_PCISTATE, val); + } /* Clear statistics/status block in chip, and status block in ram. */ for (i = NIC_SRAM_STATS_BLK; @@ -3371,7 +3983,10 @@ static int tg3_reset_hw(struct tg3 *tp) /* Initialize MBUF/DESC pool. */ tw32(BUFMGR_MB_POOL_ADDR, NIC_SRAM_MBUF_POOL_BASE); - tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) + tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE64); + else + tw32(BUFMGR_MB_POOL_SIZE, NIC_SRAM_MBUF_POOL_SIZE96); tw32(BUFMGR_DMA_DESC_POOL_ADDR, NIC_SRAM_DMA_DESC_POOL_BASE); tw32(BUFMGR_DMA_DESC_POOL_SIZE, NIC_SRAM_DMA_DESC_POOL_SIZE); @@ -3491,6 +4106,8 @@ static int tg3_reset_hw(struct tg3 *tp) tp->tx_cons = 0; tw32_mailbox(MAILBOX_SNDHOST_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); tw32_mailbox(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW, 0); + if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + tr32(MAILBOX_SNDNIC_PROD_IDX_0 + TG3_64BIT_REG_LOW); if (tp->tg3_flags & TG3_FLAG_HOST_TXDS) { tg3_set_bdinfo(tp, NIC_SRAM_SEND_RCB, @@ -3512,6 +4129,8 @@ static int tg3_reset_hw(struct tg3 *tp) tp->rx_rcb_ptr = 0; tw32_mailbox(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW, 0); + if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + tr32(MAILBOX_RCVRET_CON_IDX_0 + TG3_64BIT_REG_LOW); tg3_set_bdinfo(tp, NIC_SRAM_RCV_RET_RCB, tp->rx_rcb_mapping, @@ -3522,10 +4141,14 @@ static int tg3_reset_hw(struct tg3 *tp) tp->rx_std_ptr = tp->rx_pending; tw32_mailbox(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW, tp->rx_std_ptr); + if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + tr32(MAILBOX_RCV_STD_PROD_IDX + TG3_64BIT_REG_LOW); #if TG3_MINI_RING_WORKS tp->rx_mini_ptr = tp->rx_mini_pending; tw32_mailbox(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW, tp->rx_mini_ptr); + if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + tr32(MAILBOX_RCV_MINI_PROD_IDX + TG3_64BIT_REG_LOW); #endif if (tp->tg3_flags & TG3_FLAG_JUMBO_ENABLE) @@ -3534,6 +4157,8 @@ static int tg3_reset_hw(struct tg3 *tp) tp->rx_jumbo_ptr = 0; tw32_mailbox(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW, tp->rx_jumbo_ptr); + if (tp->tg3_flags & TG3_FLAG_MBOX_WRITE_REORDER) + tr32(MAILBOX_RCV_JUMBO_PROD_IDX + TG3_64BIT_REG_LOW); /* Initialize MAC address and backoff seed. */ __tg3_set_mac_addr(tp); @@ -3601,25 +4226,53 @@ static int tg3_reset_hw(struct tg3 *tp) tp->mac_mode = MAC_MODE_TXSTAT_ENABLE | MAC_MODE_RXSTAT_ENABLE | MAC_MODE_TDE_ENABLE | MAC_MODE_RDE_ENABLE | MAC_MODE_FHDE_ENABLE; tw32(MAC_MODE, tp->mac_mode | MAC_MODE_RXSTAT_CLEAR | MAC_MODE_TXSTAT_CLEAR); + tr32(MAC_MODE); + udelay(40); - tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_GPIO_OE1 | - GRC_LCLCTRL_GPIO_OUTPUT1 | GRC_LCLCTRL_AUTO_SEEPROM; + tp->grc_local_ctrl = GRC_LCLCTRL_INT_ON_ATTN | GRC_LCLCTRL_AUTO_SEEPROM; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5700) + tp->grc_local_ctrl |= (GRC_LCLCTRL_GPIO_OE1 | + GRC_LCLCTRL_GPIO_OUTPUT1); tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl); + tr32(GRC_LOCAL_CTRL); + udelay(100); tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0); + tr32(MAILBOX_INTERRUPT_0); tw32(DMAC_MODE, DMAC_MODE_ENABLE); + tr32(DMAC_MODE); + udelay(40); tw32(WDMAC_MODE, (WDMAC_MODE_ENABLE | WDMAC_MODE_TGTABORT_ENAB | WDMAC_MODE_MSTABORT_ENAB | WDMAC_MODE_PARITYERR_ENAB | WDMAC_MODE_ADDROFLOW_ENAB | WDMAC_MODE_FIFOOFLOW_ENAB | WDMAC_MODE_FIFOURUN_ENAB | WDMAC_MODE_FIFOOREAD_ENAB | WDMAC_MODE_LNGREAD_ENAB)); - tw32(RDMAC_MODE, (RDMAC_MODE_ENABLE | RDMAC_MODE_TGTABORT_ENAB | - RDMAC_MODE_MSTABORT_ENAB | RDMAC_MODE_PARITYERR_ENAB | - RDMAC_MODE_ADDROFLOW_ENAB | RDMAC_MODE_FIFOOFLOW_ENAB | - RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB | - RDMAC_MODE_LNGREAD_ENAB)); + tr32(WDMAC_MODE); + udelay(40); + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && + (tp->tg3_flags & TG3_FLAG_PCIX_MODE)) { + val = tr32(TG3PCI_X_CAPS); + val &= ~(PCIX_CAPS_SPLIT_MASK | PCIX_CAPS_BURST_MASK); + val |= (PCIX_CAPS_MAX_BURST_5704 << PCIX_CAPS_BURST_SHIFT); + if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE) + val |= (tp->split_mode_max_reqs << + PCIX_CAPS_SPLIT_SHIFT); + tw32(TG3PCI_X_CAPS, val); + } + + val = (RDMAC_MODE_ENABLE | RDMAC_MODE_TGTABORT_ENAB | + RDMAC_MODE_MSTABORT_ENAB | RDMAC_MODE_PARITYERR_ENAB | + RDMAC_MODE_ADDROFLOW_ENAB | RDMAC_MODE_FIFOOFLOW_ENAB | + RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB | + RDMAC_MODE_LNGREAD_ENAB); + if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE) + val |= RDMAC_MODE_SPLIT_ENABLE; + tw32(RDMAC_MODE, val); + tr32(RDMAC_MODE); + udelay(40); tw32(RCVDCC_MODE, RCVDCC_MODE_ENABLE | RCVDCC_MODE_ATTN_ENABLE); tw32(MBFREE_MODE, MBFREE_MODE_ENABLE); @@ -3637,10 +4290,21 @@ static int tg3_reset_hw(struct tg3 *tp) return err; } +#if TG3_DO_TSO != 0 + err = tg3_load_tso_firmware(tp); + if (err) + return err; +#endif + tp->tx_mode = TX_MODE_ENABLE; tw32(MAC_TX_MODE, tp->tx_mode); + tr32(MAC_TX_MODE); + udelay(100); + tp->rx_mode = RX_MODE_ENABLE; tw32(MAC_RX_MODE, tp->rx_mode); + tr32(MAC_RX_MODE); + udelay(10); if (tp->link_config.phy_is_low_power) { tp->link_config.phy_is_low_power = 0; @@ -3651,11 +4315,17 @@ static int tg3_reset_hw(struct tg3 *tp) tp->mi_mode = MAC_MI_MODE_BASE; tw32(MAC_MI_MODE, tp->mi_mode); + tr32(MAC_MI_MODE); + udelay(40); + tw32(MAC_LED_CTRL, 0); tw32(MAC_MI_STAT, MAC_MI_STAT_LNKSTAT_ATTN_ENAB); tw32(MAC_RX_MODE, RX_MODE_RESET); + tr32(MAC_RX_MODE); udelay(10); tw32(MAC_RX_MODE, tp->rx_mode); + tr32(MAC_RX_MODE); + udelay(10); if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1) tw32(MAC_SERDES_CFG, 0x616000); @@ -3738,7 +4408,7 @@ static void tg3_timer(unsigned long __opaque) tw32(GRC_LOCAL_CTRL, tp->grc_local_ctrl | GRC_LCLCTRL_SETINT); } else { - tw32(HOSTCC_MODE, + tw32(HOSTCC_MODE, tp->coalesce_mode | (HOSTCC_MODE_ENABLE | HOSTCC_MODE_NOW)); } @@ -3781,8 +4451,11 @@ static void tg3_timer(unsigned long __opaque) tw32(MAC_MODE, (tp->mac_mode & ~MAC_MODE_PORT_MODE_MASK)); + tr32(MAC_MODE); udelay(40); tw32(MAC_MODE, tp->mac_mode); + tr32(MAC_MODE); + udelay(40); tg3_setup_phy(tp); } } @@ -3790,6 +4463,21 @@ static void tg3_timer(unsigned long __opaque) tp->timer_counter = tp->timer_multiplier; } + /* Heartbeat is only sent once every 120 seconds. */ + if (!--tp->asf_counter) { + if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) { + u32 val; + + tg3_write_mem(tp, NIC_SRAM_FW_CMD_MBOX, FWCMD_NICDRV_ALIVE); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_LEN_MBOX, 4); + tg3_write_mem(tp, NIC_SRAM_FW_CMD_DATA_MBOX, 3); + val = tr32(GRC_RX_CPU_EVENT); + val |= (1 << 14); + tw32(GRC_RX_CPU_EVENT, val); + } + tp->asf_counter = tp->asf_multiplier; + } + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); @@ -3838,6 +4526,7 @@ static int tg3_open(struct net_device *dev) } else { tp->timer_offset = HZ / 10; tp->timer_counter = tp->timer_multiplier = 10; + tp->asf_counter = tp->asf_multiplier = (10 * 120); init_timer(&tp->timer); tp->timer.expires = jiffies + tp->timer_offset; @@ -4272,10 +4961,10 @@ static inline u32 calc_crc(unsigned char *buf, int len) static void tg3_set_multi(struct tg3 *tp, unsigned int accept_all) { /* accept or reject all multicast frames */ - tw32 (MAC_HASH_REG_0, accept_all ? 0xffffffff : 0); - tw32 (MAC_HASH_REG_1, accept_all ? 0xffffffff : 0); - tw32 (MAC_HASH_REG_2, accept_all ? 0xffffffff : 0); - tw32 (MAC_HASH_REG_3, accept_all ? 0xffffffff : 0); + tw32(MAC_HASH_REG_0, accept_all ? 0xffffffff : 0); + tw32(MAC_HASH_REG_1, accept_all ? 0xffffffff : 0); + tw32(MAC_HASH_REG_2, accept_all ? 0xffffffff : 0); + tw32(MAC_HASH_REG_3, accept_all ? 0xffffffff : 0); } static void __tg3_set_rx_mode(struct net_device *dev) @@ -4283,7 +4972,17 @@ static void __tg3_set_rx_mode(struct net_device *dev) struct tg3 *tp = dev->priv; u32 rx_mode; - rx_mode = tp->rx_mode & ~RX_MODE_PROMISC; + rx_mode = tp->rx_mode & ~(RX_MODE_PROMISC | + RX_MODE_KEEP_VLAN_TAG); +#if TG3_VLAN_TAG_USED + if (!tp->vlgrp) + rx_mode |= RX_MODE_KEEP_VLAN_TAG; +#else + /* By definition, VLAN is disabled always in this + * case. + */ + rx_mode |= RX_MODE_KEEP_VLAN_TAG; +#endif if (dev->flags & IFF_PROMISC) { /* Promiscuous mode. */ @@ -4313,15 +5012,17 @@ static void __tg3_set_rx_mode(struct net_device *dev) mc_filter[regidx] |= (1 << bit); } - tw32 (MAC_HASH_REG_0, mc_filter[0]); - tw32 (MAC_HASH_REG_1, mc_filter[1]); - tw32 (MAC_HASH_REG_2, mc_filter[2]); - tw32 (MAC_HASH_REG_3, mc_filter[3]); + tw32(MAC_HASH_REG_0, mc_filter[0]); + tw32(MAC_HASH_REG_1, mc_filter[1]); + tw32(MAC_HASH_REG_2, mc_filter[2]); + tw32(MAC_HASH_REG_3, mc_filter[3]); } if (rx_mode != tp->rx_mode) { tp->rx_mode = rx_mode; - tw32 (MAC_RX_MODE, rx_mode); + tw32(MAC_RX_MODE, rx_mode); + tr32(MAC_RX_MODE); + udelay(10); } } @@ -4837,7 +5538,12 @@ static void tg3_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) spin_lock_irq(&tp->lock); spin_lock(&tp->tx_lock); + tp->vlgrp = grp; + + /* Update RX_MODE_KEEP_VLAN_TAG bit in RX_MODE register. */ + __tg3_set_rx_mode(dev); + spin_unlock(&tp->tx_lock); spin_unlock_irq(&tp->lock); } @@ -4872,6 +5578,7 @@ static void __devinit tg3_nvram_init(struct tg3 *tp) /* Enable seeprom accesses. */ tw32(GRC_LOCAL_CTRL, tr32(GRC_LOCAL_CTRL) | GRC_LCLCTRL_AUTO_SEEPROM); + tr32(GRC_LOCAL_CTRL); udelay(100); if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5700 && @@ -5079,11 +5786,14 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) eeprom_led_mode = led_mode_auto; break; }; - } + if ((tp->pci_chip_rev_id == CHIPREV_ID_5703_A1 || + tp->pci_chip_rev_id == CHIPREV_ID_5703_A2) && + (nic_cfg & NIC_SRAM_DATA_CFG_EEPROM_WP)) + tp->tg3_flags |= TG3_FLAG_EEPROM_WRITE_PROT; - err = tg3_phy_reset(tp, 0); - if (err) - return err; + if (nic_cfg & NIC_SRAM_DATA_CFG_ASF_ENABLE) + tp->tg3_flags |= TG3_FLAG_ENABLE_ASF; + } /* Now read the physical PHY_ID from the chip and verify * that it is sane. If it doesn't look good, we fall back @@ -5114,30 +5824,24 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) } } - if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) { - tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); - tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f); - tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x2aaa); - } + err = tg3_phy_reset(tp, 1); + if (err) + return err; if (tp->pci_chip_rev_id == CHIPREV_ID_5701_A0 || - tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) - tp->tg3_flags |= TG3_FLAG_PHY_RESET_ON_INIT; - - if (tp->tg3_flags & TG3_FLAG_PHY_RESET_ON_INIT) { + tp->pci_chip_rev_id == CHIPREV_ID_5701_B0) { u32 mii_tg3_ctrl; - - err = tg3_phy_reset(tp, 1); - if (err) - return err; - - /* These chips, when reset, only advertise 10Mb capabilities. - * Fix that. + + /* These chips, when reset, only advertise 10Mb + * capabilities. Fix that. */ err = tg3_writephy(tp, MII_ADVERTISE, (ADVERTISE_CSMA | - ADVERTISE_10HALF | ADVERTISE_10FULL | - ADVERTISE_100HALF | ADVERTISE_100FULL)); + ADVERTISE_PAUSE_CAP | + ADVERTISE_10HALF | + ADVERTISE_10FULL | + ADVERTISE_100HALF | + ADVERTISE_100FULL)); mii_tg3_ctrl = (MII_TG3_CTRL_ADV_1000_HALF | MII_TG3_CTRL_ADV_1000_FULL | MII_TG3_CTRL_AS_MASTER | @@ -5150,6 +5854,22 @@ static int __devinit tg3_phy_probe(struct tg3 *tp) (BMCR_ANRESTART | BMCR_ANENABLE)); } + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5703) { + tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x0c00); + tg3_writephy(tp, MII_TG3_DSP_ADDRESS, 0x201f); + tg3_writephy(tp, MII_TG3_DSP_RW_PORT, 0x2aaa); + } + + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { + tg3_writephy(tp, 0x1c, 0x8d68); + tg3_writephy(tp, 0x1c, 0x8d68); + } + + /* Enable Ethernet@WireSpeed */ + tg3_writephy(tp, MII_TG3_AUX_CTRL, 0x7007); + tg3_readphy(tp, MII_TG3_AUX_CTRL, &val); + tg3_writephy(tp, MII_TG3_AUX_CTRL, (val | (1 << 15) | (1 << 4))); + if (!err && ((tp->phy_id & PHY_ID_MASK) == PHY_ID_BCM5401)) { err = tg3_init_5401phy_dsp(tp); } @@ -5247,6 +5967,20 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) u16 pci_cmd; int err; + /* If we have an AMD 762 or Intel ICH/ICH0 chipset, write + * reordering to the mailbox registers done by the host + * controller can cause major troubles. We read back from + * every mailbox register write to force the writes to be + * posted to the chip in order. + */ + if (pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82801AA_8, NULL) || + pci_find_device(PCI_VENDOR_ID_INTEL, + PCI_DEVICE_ID_INTEL_82801AB_8, NULL) || + pci_find_device(PCI_VENDOR_ID_AMD, + PCI_DEVICE_ID_AMD_FE_GATE_700C, NULL)) + tp->tg3_flags |= TG3_FLAG_MBOX_WRITE_REORDER; + /* Force memory write invalidate off. If we leave it on, * then on 5700_BX chips we have to enable a workaround. * The workaround is to set the TG3PCI_DMA_RW_CTRL boundry @@ -5258,12 +5992,24 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) pci_cmd &= ~PCI_COMMAND_INVALIDATE; pci_write_config_word(tp->pdev, PCI_COMMAND, pci_cmd); + /* It is absolutely critical that TG3PCI_MISC_HOST_CTRL + * has the register indirect write enable bit set before + * we try to access any of the MMIO registers. It is also + * critical that the PCI-X hw workaround situation is decided + * before that as well. + */ pci_read_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, &misc_ctrl_reg); tp->pci_chip_rev_id = (misc_ctrl_reg >> MISC_HOST_CTRL_CHIPREV_SHIFT); + /* Initialize misc host control in PCI block. */ + tp->misc_host_ctrl |= (misc_ctrl_reg & + MISC_HOST_CTRL_CHIPREV); + pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, + tp->misc_host_ctrl); + pci_read_config_dword(tp->pdev, TG3PCI_CACHELINESZ, &cacheline_sz_reg); @@ -5377,14 +6123,9 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) GET_CHIP_REV(tp->pci_chip_rev_id) != CHIPREV_5700_BX) tp->coalesce_mode |= HOSTCC_MODE_32BYTE; - /* Initialize misc host control in PCI block. */ - tp->misc_host_ctrl |= (misc_ctrl_reg & - MISC_HOST_CTRL_CHIPREV); - pci_write_config_dword(tp->pdev, TG3PCI_MISC_HOST_CTRL, - tp->misc_host_ctrl); - /* Initialize MAC MI mode, polling disabled. */ tw32(MAC_MI_MODE, tp->mi_mode); + tr32(MAC_MI_MODE); udelay(40); /* Initialize data/descriptor byte/word swapping. */ @@ -5439,9 +6180,16 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5702FE && grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5703 && grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5703S && + grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_5704 && grc_misc_cfg != GRC_MISC_CFG_BOARD_ID_AC91002A1) return -ENODEV; + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704 && + grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5704CIOBE) { + tp->tg3_flags |= TG3_FLAG_SPLIT_MODE; + tp->split_mode_max_reqs = SPLIT_MODE_5704_MAX_REQ; + } + /* ROFL, you should see Broadcom's driver code implementing * this, stuff like "if (a || b)" where a and b are always * mutually exclusive. DaveM finds like 6 bugs today, hello! @@ -5520,13 +6268,23 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) (tp->tg3_flags & TG3_FLAG_PCIX_MODE) != 0) tp->rx_offset = 0; + /* By default, disable wake-on-lan. User can change this + * using ETHTOOL_SWOL. + */ + tp->tg3_flags &= ~TG3_FLAG_WOL_ENABLE; + return err; } static int __devinit tg3_get_device_address(struct tg3 *tp) { struct net_device *dev = tp->dev; - u32 hi, lo; + u32 hi, lo, mac_offset; + + if (PCI_FUNC(tp->pdev->devfn) == 0) + mac_offset = 0x7c; + else + mac_offset = 0xcc; /* First try to get it from MAC address mailbox. */ tg3_read_mem(tp, NIC_SRAM_MAC_ADDR_HIGH_MBOX, &hi); @@ -5541,8 +6299,8 @@ static int __devinit tg3_get_device_address(struct tg3 *tp) dev->dev_addr[5] = (lo >> 0) & 0xff; } /* Next, try NVRAM. */ - else if (!tg3_nvram_read(tp, 0x7c, &hi) && - !tg3_nvram_read(tp, 0x80, &lo)) { + else if (!tg3_nvram_read(tp, mac_offset + 0, &hi) && + !tg3_nvram_read(tp, mac_offset + 4, &lo)) { dev->dev_addr[0] = ((hi >> 16) & 0xff); dev->dev_addr[1] = ((hi >> 24) & 0xff); dev->dev_addr[2] = ((lo >> 0) & 0xff); @@ -5593,11 +6351,21 @@ static int __devinit tg3_do_test_dma(struct tg3 *tp, u32 *buf, dma_addr_t buf_dm if (to_device) { test_desc.cqid_sqid = (13 << 8) | 2; tw32(RDMAC_MODE, RDMAC_MODE_RESET); + tr32(RDMAC_MODE); + udelay(40); + tw32(RDMAC_MODE, RDMAC_MODE_ENABLE); + tr32(RDMAC_MODE); + udelay(40); } else { test_desc.cqid_sqid = (16 << 8) | 7; tw32(WDMAC_MODE, WDMAC_MODE_RESET); + tr32(WDMAC_MODE); + udelay(40); + tw32(WDMAC_MODE, WDMAC_MODE_ENABLE); + tr32(WDMAC_MODE); + udelay(40); } test_desc.flags = 0x00000004; @@ -5660,16 +6428,26 @@ static int __devinit tg3_test_dma(struct tg3 *tp) (0x7 << DMA_RWCTRL_READ_WATER_SHIFT) | (0x0f << DMA_RWCTRL_MIN_DMA_SHIFT); } else { - tp->dma_rwctrl = - (0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) | - (0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) | - (0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) | - (0x3 << DMA_RWCTRL_READ_WATER_SHIFT) | - (0x0f << DMA_RWCTRL_MIN_DMA_SHIFT); + if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) + tp->dma_rwctrl = + (0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) | + (0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) | + (0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) | + (0x7 << DMA_RWCTRL_READ_WATER_SHIFT) | + (0x00 << DMA_RWCTRL_MIN_DMA_SHIFT); + else + tp->dma_rwctrl = + (0x7 << DMA_RWCTRL_PCI_WRITE_CMD_SHIFT) | + (0x6 << DMA_RWCTRL_PCI_READ_CMD_SHIFT) | + (0x3 << DMA_RWCTRL_WRITE_WATER_SHIFT) | + (0x3 << DMA_RWCTRL_READ_WATER_SHIFT) | + (0x0f << DMA_RWCTRL_MIN_DMA_SHIFT); /* Wheee, some more chip bugs... */ if (tp->pci_chip_rev_id == CHIPREV_ID_5703_A1 || - tp->pci_chip_rev_id == CHIPREV_ID_5703_A2) + tp->pci_chip_rev_id == CHIPREV_ID_5703_A2 || + tp->pci_chip_rev_id == CHIPREV_ID_5703_A3 || + tp->pci_chip_rev_id == CHIPREV_ID_5704_A0) tp->dma_rwctrl |= DMA_RWCTRL_ONE_DMA; } @@ -5844,6 +6622,7 @@ static char * __devinit tg3_phy_string(struct tg3 *tp) case PHY_ID_BCM5411: return "5411"; case PHY_ID_BCM5701: return "5701"; case PHY_ID_BCM5703: return "5703"; + case PHY_ID_BCM5704: return "5704"; case PHY_ID_BCM8002: return "8002"; case PHY_ID_SERDES: return "serdes"; default: return "unknown"; @@ -5925,6 +6704,9 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, dev->vlan_rx_register = tg3_vlan_rx_register; dev->vlan_rx_kill_vid = tg3_vlan_rx_kill_vid; #endif +#if TG3_DO_TSO != 0 + dev->features |= NETIF_F_TSO; +#endif tp = dev->priv; tp->pdev = pdev; diff --git a/drivers/net/tg3.h b/drivers/net/tg3.h index 02b7b77d5f4c..754f638f890a 100644 --- a/drivers/net/tg3.h +++ b/drivers/net/tg3.h @@ -58,6 +58,11 @@ #define TG3PCI_MAX_LAT 0x0000003f #define TG3PCI_X_CAPS 0x00000040 #define PCIX_CAPS_RELAXED_ORDERING 0x00020000 +#define PCIX_CAPS_SPLIT_MASK 0x00700000 +#define PCIX_CAPS_SPLIT_SHIFT 20 +#define PCIX_CAPS_BURST_MASK 0x000c0000 +#define PCIX_CAPS_BURST_SHIFT 18 +#define PCIX_CAPS_MAX_BURST_5704 2 #define TG3PCI_PM_CAP_PTR 0x00000041 #define TG3PCI_X_COMMAND 0x00000042 #define TG3PCI_X_STATUS 0x00000044 @@ -109,10 +114,13 @@ #define CHIPREV_ID_5703_A0 0x1000 #define CHIPREV_ID_5703_A1 0x1001 #define CHIPREV_ID_5703_A2 0x1002 +#define CHIPREV_ID_5703_A3 0x1003 +#define CHIPREV_ID_5704_A0 0x2000 #define GET_ASIC_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 12) #define ASIC_REV_5700 0x07 #define ASIC_REV_5701 0x00 #define ASIC_REV_5703 0x01 +#define ASIC_REV_5704 0x02 #define GET_CHIP_REV(CHIP_REV_ID) ((CHIP_REV_ID) >> 8) #define CHIPREV_5700_AX 0x70 #define CHIPREV_5700_BX 0x71 @@ -165,6 +173,7 @@ #define PCISTATE_ROM_ENABLE 0x00000020 #define PCISTATE_ROM_RETRY_ENABLE 0x00000040 #define PCISTATE_FLAT_VIEW 0x00000100 +#define PCISTATE_RETRY_SAME_DMA 0x00002000 #define TG3PCI_CLOCK_CTRL 0x00000074 #define CLOCK_CTRL_CORECLK_DISABLE 0x00000200 #define CLOCK_CTRL_RXCLK_DISABLE 0x00000400 @@ -843,6 +852,8 @@ #define RDMAC_MODE_FIFOURUN_ENAB 0x00000080 #define RDMAC_MODE_FIFOOREAD_ENAB 0x00000100 #define RDMAC_MODE_LNGREAD_ENAB 0x00000200 +#define RDMAC_MODE_SPLIT_ENABLE 0x00000800 +#define RDMAC_MODE_SPLIT_RESET 0x00001000 #define RDMAC_STATUS 0x00004804 #define RDMAC_STATUS_TGTABORT 0x00000004 #define RDMAC_STATUS_MSTABORT 0x00000008 @@ -1126,6 +1137,8 @@ #define GRC_MISC_CFG_BOARD_ID_5702FE 0x00004000 #define GRC_MISC_CFG_BOARD_ID_5703 0x00000000 #define GRC_MISC_CFG_BOARD_ID_5703S 0x00002000 +#define GRC_MISC_CFG_BOARD_ID_5704 0x00000000 +#define GRC_MISC_CFG_BOARD_ID_5704CIOBE 0x00004000 #define GRC_MISC_CFG_BOARD_ID_AC91002A1 0x00018000 #define GRC_LOCAL_CTRL 0x00006808 #define GRC_LCLCTRL_INT_ACTIVE 0x00000001 @@ -1248,14 +1261,19 @@ #define NIC_SRAM_DATA_SIG_MAGIC 0x4b657654 /* ascii for 'KevT' */ #define NIC_SRAM_DATA_CFG 0x00000b58 -#define NIC_SRAM_DATA_CFG_PHY_TYPE_MASK 0x0000000c -#define NIC_SRAM_DATA_CFG_PHY_TYPE_UNKNOWN 0x00000000 -#define NIC_SRAM_DATA_CFG_PHY_TYPE_COPPER 0x00000004 -#define NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER 0x00000008 -#define NIC_SRAM_DATA_CFG_LED_MODE_MASK 0x00000030 +#define NIC_SRAM_DATA_CFG_LED_MODE_MASK 0x0000000c #define NIC_SRAM_DATA_CFG_LED_MODE_UNKNOWN 0x00000000 -#define NIC_SRAM_DATA_CFG_LED_TRIPLE_SPD 0x00000010 -#define NIC_SRAM_DATA_CFG_LED_LINK_SPD 0x00000020 +#define NIC_SRAM_DATA_CFG_LED_TRIPLE_SPD 0x00000004 +#define NIC_SRAM_DATA_CFG_LED_OPEN_DRAIN 0x00000004 +#define NIC_SRAM_DATA_CFG_LED_LINK_SPD 0x00000008 +#define NIC_SRAM_DATA_CFG_LED_OUTPUT 0x00000008 +#define NIC_SRAM_DATA_CFG_PHY_TYPE_MASK 0x00000030 +#define NIC_SRAM_DATA_CFG_PHY_TYPE_UNKNOWN 0x00000000 +#define NIC_SRAM_DATA_CFG_PHY_TYPE_COPPER 0x00000010 +#define NIC_SRAM_DATA_CFG_PHY_TYPE_FIBER 0x00000020 +#define NIC_SRAM_DATA_CFG_WOL_ENABLE 0x00000040 +#define NIC_SRAM_DATA_CFG_ASF_ENABLE 0x00000080 +#define NIC_SRAM_DATA_CFG_EEPROM_WP 0x00000100 #define NIC_SRAM_DATA_PHY_ID 0x00000b74 #define NIC_SRAM_DATA_PHY_ID1_MASK 0xffff0000 @@ -1292,7 +1310,8 @@ #define NIC_SRAM_RX_BUFFER_DESC 0x00006000 /* 256 entries */ #define NIC_SRAM_RX_JUMBO_BUFFER_DESC 0x00007000 /* 256 entries */ #define NIC_SRAM_MBUF_POOL_BASE 0x00008000 -#define NIC_SRAM_MBUF_POOL_SIZE 0x00018000 +#define NIC_SRAM_MBUF_POOL_SIZE96 0x00018000 +#define NIC_SRAM_MBUF_POOL_SIZE64 0x00018000 /* Currently this is fixed. */ #define PHY_ADDR 0x01 @@ -1410,6 +1429,7 @@ struct tg3_tx_buffer_desc { u32 vlan_tag; #define TXD_VLAN_TAG_SHIFT 0 +#define TXD_MSS_SHIFT 16 }; #define TXD_ADDR 0x00UL /* 64-bit */ @@ -1660,6 +1680,12 @@ struct ring_info { DECLARE_PCI_UNMAP_ADDR(mapping) }; +struct tx_ring_info { + struct sk_buff *skb; + DECLARE_PCI_UNMAP_ADDR(mapping) + u32 prev_vlan_tag; +}; + struct tg3_config_info { u32 flags; }; @@ -1737,11 +1763,13 @@ struct tg3 { #define TG3_FLAG_RX_CHECKSUMS 0x00000004 #define TG3_FLAG_USE_LINKCHG_REG 0x00000008 #define TG3_FLAG_USE_MI_INTERRUPT 0x00000010 +#define TG3_FLAG_ENABLE_ASF 0x00000020 #define TG3_FLAG_POLL_SERDES 0x00000080 -#define TG3_FLAG_PHY_RESET_ON_INIT 0x00000100 +#define TG3_FLAG_MBOX_WRITE_REORDER 0x00000100 #define TG3_FLAG_PCIX_TARGET_HWBUG 0x00000200 #define TG3_FLAG_WOL_SPEED_100MB 0x00000400 -#define TG3_FLAG_WOL_ENABLE 0x00001000 +#define TG3_FLAG_WOL_ENABLE 0x00000800 +#define TG3_FLAG_EEPROM_WRITE_PROT 0x00001000 #define TG3_FLAG_NVRAM 0x00002000 #define TG3_FLAG_NVRAM_BUFFERED 0x00004000 #define TG3_FLAG_RX_PAUSE 0x00008000 @@ -1759,14 +1787,20 @@ struct tg3 { #define TG3_FLAG_PAUSE_TX 0x08000000 #define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000 #define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000 +#define TG3_FLAG_SPLIT_MODE 0x40000000 #define TG3_FLAG_INIT_COMPLETE 0x80000000 u32 msg_enable; + u32 split_mode_max_reqs; +#define SPLIT_MODE_5704_MAX_REQ 3 + struct timer_list timer; u16 timer_counter; u16 timer_multiplier; u32 timer_offset; + u16 asf_counter; + u16 asf_multiplier; struct tg3_link_config link_config; struct tg3_bufmgr_config bufmgr_config; @@ -1807,6 +1841,7 @@ struct tg3 { #define PHY_ID_BCM5411 0x60008070 #define PHY_ID_BCM5701 0x60008110 #define PHY_ID_BCM5703 0x60008160 +#define PHY_ID_BCM5704 0x60008190 #define PHY_ID_BCM8002 0x60010140 #define PHY_ID_SERDES 0xfeedbee0 #define PHY_ID_INVALID 0xffffffff @@ -1826,7 +1861,7 @@ struct tg3 { #define KNOWN_PHY_ID(X) \ ((X) == PHY_ID_BCM5400 || (X) == PHY_ID_BCM5401 || \ (X) == PHY_ID_BCM5411 || (X) == PHY_ID_BCM5701 || \ - (X) == PHY_ID_BCM5703 || \ + (X) == PHY_ID_BCM5703 || (X) == PHY_ID_BCM5704 || \ (X) == PHY_ID_BCM8002 || (X) == PHY_ID_SERDES) unsigned long regs; @@ -1853,7 +1888,7 @@ struct tg3 { /* TX descs are only used if TG3_FLAG_HOST_TXDS is set. */ struct tg3_tx_buffer_desc *tx_ring; - struct ring_info *tx_buffers; + struct tx_ring_info *tx_buffers; dma_addr_t tx_desc_mapping; struct tg3_hw_status *hw_status; diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids index 186c8fdd99ad..3290c4213660 100644 --- a/drivers/pci/pci.ids +++ b/drivers/pci/pci.ids @@ -5053,6 +5053,7 @@ 14e4 000b BCM5703 1000BaseTX 14e4 8009 BCM5703 1000BaseTX 14e4 800a BCM5703 1000BaseTX + 1648 NetXtreme BCM5704 Gigabit Ethernet 164d NetXtreme BCM5702FE Gigabit Ethernet 16a6 NetXtreme BCM5702X Gigabit Ethernet 16a7 NetXtreme BCM5703X Gigabit Ethernet diff --git a/include/linux/llc.h b/include/linux/llc.h index 824a149e9e6b..77ac5d9df544 100644 --- a/include/linux/llc.h +++ b/include/linux/llc.h @@ -78,17 +78,6 @@ enum llc_sockopts { #define LLC_SAP_DYN_STOP 0xDE #define LLC_SAP_DYN_TRIES 4 -struct sock; - -struct llc_ui_opt { - u16 link; /* network layer link number */ - struct llc_sap *sap; /* pointer to parent SAP */ - struct sock *core_sk; - struct net_device *dev; /* device to send to remote */ - struct sockaddr_llc addr; /* address sock is bound to */ -}; - -#define llc_ui_sk(__sk) ((struct llc_ui_opt *)(__sk)->protinfo) #define llc_ui_skb_cb(__skb) ((struct sockaddr_llc *)&((__skb)->cb[0])) #ifdef CONFIG_LLC_UI diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h index 5eea9545b69a..9a1ad256e2cc 100644 --- a/include/linux/pci_ids.h +++ b/include/linux/pci_ids.h @@ -1561,6 +1561,7 @@ #define PCI_DEVICE_ID_TIGON3_5701 0x1645 #define PCI_DEVICE_ID_TIGON3_5702 0x1646 #define PCI_DEVICE_ID_TIGON3_5703 0x1647 +#define PCI_DEVICE_ID_TIGON3_5704 0x1648 #define PCI_DEVICE_ID_TIGON3_5702FE 0x164d #define PCI_DEVICE_ID_TIGON3_5702X 0x16a6 #define PCI_DEVICE_ID_TIGON3_5703X 0x16a7 diff --git a/include/net/llc_c_st.h b/include/net/llc_c_st.h index f0b40ed22754..0e79cfba4b3b 100644 --- a/include/net/llc_c_st.h +++ b/include/net/llc_c_st.h @@ -33,15 +33,15 @@ /* Connection state table structure */ struct llc_conn_state_trans { - llc_conn_ev_t ev; - u8 next_state; - llc_conn_ev_qfyr_t *ev_qualifiers; - llc_conn_action_t *ev_actions; + llc_conn_ev_t ev; + u8 next_state; + llc_conn_ev_qfyr_t *ev_qualifiers; + llc_conn_action_t *ev_actions; }; struct llc_conn_state { - u8 current_state; - struct llc_conn_state_trans **transitions; + u8 current_state; + struct llc_conn_state_trans **transitions; }; extern struct llc_conn_state llc_conn_state_table[]; diff --git a/include/net/llc_conn.h b/include/net/llc_conn.h index db42c7f6fc78..5846a5b91841 100644 --- a/include/net/llc_conn.h +++ b/include/net/llc_conn.h @@ -2,7 +2,7 @@ #define LLC_CONN_H /* * Copyright (c) 1997 by Procom Technology, Inc. - * 2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * 2001, 2002 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> * * This program can be redistributed or modified under the terms of the * GNU General Public License as published by the Free Software Foundation. @@ -13,8 +13,7 @@ */ #include <linux/timer.h> #include <net/llc_if.h> - -#undef DEBUG_LLC_CONN_ALLOC +#include <linux/llc.h> struct llc_timer { struct timer_list timer; @@ -25,7 +24,7 @@ struct llc_timer { struct llc_opt { struct list_head node; /* entry in sap->sk_list.list */ struct sock *sk; /* sock that has this llc_opt */ - void *handler; /* for upper layers usage */ + struct sockaddr_llc addr; /* address sock is bound to */ u8 state; /* state of connection */ struct llc_sap *sap; /* pointer to parent SAP */ struct llc_addr laddr; /* lsap/mac pair */ @@ -80,63 +79,14 @@ struct llc_opt { struct llc_conn_state_ev; -extern struct sock *__llc_sock_alloc(void); -extern void __llc_sock_free(struct sock *sk, u8 free); - -#ifdef DEBUG_LLC_CONN_ALLOC -#define dump_stack() printk(KERN_INFO "call trace: %p, %p, %p\n", \ - __builtin_return_address(0), \ - __builtin_return_address(1), \ - __builtin_return_address(2)); -#define llc_sock_alloc() ({ \ - struct sock *__sk = __llc_sock_alloc(); \ - if (__sk) { \ - llc_sk(__sk)->f_alloc = __FUNCTION__; \ - llc_sk(__sk)->l_alloc = __LINE__; \ - } \ - __sk;}) -#define __llc_sock_assert(__sk) \ - if (llc_sk(__sk)->f_free) { \ - printk(KERN_ERR \ - "%p conn (alloc'd @ %s(%d)) " \ - "already freed @ %s(%d) " \ - "being used again @ %s(%d)\n", \ - llc_sk(__sk), \ - llc_sk(__sk)->f_alloc, llc_sk(__sk)->l_alloc, \ - llc_sk(__sk)->f_free, llc_sk(__sk)->l_free, \ - __FUNCTION__, __LINE__); \ - dump_stack(); -#define llc_sock_free(__sk) \ -{ \ - __llc_sock_assert(__sk) \ - } else { \ - __llc_sock_free(__sk, 0); \ - llc_sk(__sk)->f_free = __FUNCTION__; \ - llc_sk(__sk)->l_free = __LINE__; \ - } \ -} -#define llc_sock_assert(__sk) \ -{ \ - __llc_sock_assert(__sk); \ - return; } \ -} -#define llc_sock_assert_ret(__sk, __ret) \ -{ \ - __llc_sock_assert(__sk); \ - return __ret; } \ -} -#else /* DEBUG_LLC_CONN_ALLOC */ -#define llc_sock_alloc() __llc_sock_alloc() -#define llc_sock_free(__sk) __llc_sock_free(__sk, 1) -#define llc_sock_assert(__sk) -#define llc_sock_assert_ret(__sk) -#endif /* DEBUG_LLC_CONN_ALLOC */ +extern struct sock *llc_sk_alloc(int family, int priority); +extern void llc_sk_free(struct sock *sk); -extern void llc_sock_reset(struct sock *sk); -extern int llc_sock_init(struct sock *sk); +extern void llc_sk_reset(struct sock *sk); +extern int llc_sk_init(struct sock *sk); /* Access to a connection */ -extern int llc_conn_send_ev(struct sock *sk, struct sk_buff *skb); +extern int llc_conn_state_process(struct sock *sk, struct sk_buff *skb); extern void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb); extern void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb); extern void llc_conn_free_ev(struct sk_buff *skb); @@ -146,8 +96,11 @@ extern void llc_conn_resend_i_pdu_as_rsp(struct sock *sk, u8 nr, u8 first_f_bit); extern int llc_conn_remove_acked_pdus(struct sock *conn, u8 nr, u16 *how_many_unacked); -extern struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr, - struct llc_addr *laddr); +extern struct sock *llc_lookup_established(struct llc_sap *sap, + struct llc_addr *daddr, + struct llc_addr *laddr); +extern struct sock *llc_lookup_listener(struct llc_sap *sap, + struct llc_addr *laddr); extern u8 llc_data_accept_state(u8 state); extern void llc_build_offset_table(void); #endif /* LLC_CONN_H */ diff --git a/include/net/llc_if.h b/include/net/llc_if.h index cc2348004161..e17373a17c00 100644 --- a/include/net/llc_if.h +++ b/include/net/llc_if.h @@ -14,13 +14,15 @@ /* Defines LLC interface to network layer */ /* Available primitives */ #include <linux/if.h> +#include <linux/if_arp.h> +#include <linux/llc.h> #define LLC_DATAUNIT_PRIM 0 #define LLC_CONN_PRIM 1 #define LLC_DATA_PRIM 2 #define LLC_DISC_PRIM 3 #define LLC_RESET_PRIM 4 -#define LLC_FLOWCONTROL_PRIM 5 +#define LLC_FLOWCONTROL_PRIM 5 /* Not supported at this time */ #define LLC_DISABLE_PRIM 6 #define LLC_XID_PRIM 7 #define LLC_TEST_PRIM 8 @@ -65,46 +67,12 @@ struct llc_addr { u8 mac[IFHWADDRLEN]; }; -/* Primitive-specific data */ -struct llc_prim_conn { - struct llc_addr saddr; /* used by request only */ - struct llc_addr daddr; /* used by request only */ - u8 status; /* reason for failure */ - u8 pri; /* service_class */ - struct net_device *dev; - struct sock *sk; /* returned from REQUEST */ - void *handler; /* upper layer use, - stored in llc_opt->handler */ - u16 link; - struct sk_buff *skb; /* received SABME */ -}; - -struct llc_prim_disc { - struct sock *sk; - u16 link; - u8 reason; /* not used by request */ -}; - struct llc_prim_reset { struct sock *sk; u16 link; u8 reason; /* used only by indicate */ }; -struct llc_prim_flow_ctrl { - struct sock *sk; - u16 link; - u32 amount; -}; - -struct llc_prim_data { - struct sock *sk; - u16 link; - u8 pri; - struct sk_buff *skb; /* pointer to frame */ - u8 status; /* reason */ -}; - /* Sending data in conection-less mode */ struct llc_prim_unit_data { struct llc_addr saddr; @@ -129,11 +97,7 @@ struct llc_prim_test { }; union llc_u_prim_data { - struct llc_prim_conn conn; - struct llc_prim_disc disc; struct llc_prim_reset res; - struct llc_prim_flow_ctrl fc; - struct llc_prim_data data; /* data */ struct llc_prim_unit_data udata; /* unit data */ struct llc_prim_xid xid; struct llc_prim_test test; @@ -152,4 +116,30 @@ typedef int (*llc_prim_call_t)(struct llc_prim_if_block *prim_if); extern struct llc_sap *llc_sap_open(llc_prim_call_t network_indicate, llc_prim_call_t network_confirm, u8 lsap); extern void llc_sap_close(struct llc_sap *sap); + +extern int llc_establish_connection(struct sock *sk, u8 *lmac, + u8 *dmac, u8 dsap); +extern int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb); +extern void llc_build_and_send_ui_pkt(struct llc_sap *sap, + struct sk_buff *skb, + struct sockaddr_llc *addr); +extern void llc_build_and_send_xid_pkt(struct llc_sap *sap, + struct sk_buff *skb, + struct sockaddr_llc *addr); +extern void llc_build_and_send_test_pkt(struct llc_sap *sap, + struct sk_buff *skb, + struct sockaddr_llc *addr); +extern int llc_send_disc(struct sock *sk); + +/** + * llc_proto_type - return eth protocol for ARP header type + * @arphrd: ARP header type. + * + * Given an ARP header type return the corresponding ethernet protocol. + */ +static __inline__ u16 llc_proto_type(u16 arphrd) +{ + return arphrd == ARPHRD_IEEE802_TR ? + htons(ETH_P_TR_802_2) : htons(ETH_P_802_2); +} #endif /* LLC_IF_H */ diff --git a/include/net/llc_mac.h b/include/net/llc_mac.h index 9f2fb80ba98e..3ab584987448 100644 --- a/include/net/llc_mac.h +++ b/include/net/llc_mac.h @@ -2,7 +2,7 @@ #define LLC_MAC_H /* * Copyright (c) 1997 by Procom Technology, Inc. - * 2001 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> + * 2001, 2002 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> * * This program can be redistributed or modified under the terms of the * GNU General Public License as published by the Free Software Foundation. @@ -13,13 +13,12 @@ */ /* Defines MAC-layer interface to LLC layer */ extern int mac_send_pdu(struct sk_buff *skb); -extern int mac_indicate(struct sk_buff *skb, struct net_device *dev, - struct packet_type *pt); +extern int llc_rcv(struct sk_buff *skb, struct net_device *dev, + struct packet_type *pt); extern struct net_device *mac_dev_peer(struct net_device *current_dev, int type, u8 *mac); -extern int llc_pdu_router(struct llc_sap *sap, struct sock *sk, - struct sk_buff *skb, u8 type); extern u16 lan_hdrs_init(struct sk_buff *skb, u8 *sa, u8 *da); +extern int llc_conn_rcv(struct sock *sk, struct sk_buff *skb); static __inline__ void llc_set_backlog_type(struct sk_buff *skb, char type) { @@ -31,4 +30,36 @@ static __inline__ char llc_backlog_type(struct sk_buff *skb) return skb->cb[sizeof(skb->cb) - 1]; } +extern u8 llc_mac_null_var[IFHWADDRLEN]; + +/** + * llc_mac_null - determines if a address is a null mac address + * @mac: Mac address to test if null. + * + * Determines if a given address is a null mac address. Returns 0 if the + * address is not a null mac, 1 if the address is a null mac. + */ +static __inline__ int llc_mac_null(u8 *mac) +{ + return !memcmp(mac, llc_mac_null_var, IFHWADDRLEN); +} + +static __inline__ int llc_addrany(struct llc_addr *addr) +{ + return llc_mac_null(addr->mac) && !addr->lsap; +} + +/** + * llc_mac_match - determines if two mac addresses are the same + * @mac1: First mac address to compare. + * @mac2: Second mac address to compare. + * + * Determines if two given mac address are the same. Returns 0 if there + * is not a complete match up to len, 1 if a complete match up to len is + * found. + */ +static __inline__ int llc_mac_match(u8 *mac1, u8 *mac2) +{ + return !memcmp(mac1, mac2, IFHWADDRLEN); +} #endif /* LLC_MAC_H */ diff --git a/include/net/llc_main.h b/include/net/llc_main.h index e3aa4d2c7632..31810831fceb 100644 --- a/include/net/llc_main.h +++ b/include/net/llc_main.h @@ -61,8 +61,8 @@ extern void llc_sap_save(struct llc_sap *sap); extern void llc_free_sap(struct llc_sap *sap); extern struct llc_sap *llc_sap_find(u8 lsap); extern struct llc_station *llc_station_get(void); -extern void llc_station_send_ev(struct llc_station *station, - struct sk_buff *skb); +extern void llc_station_state_process(struct llc_station *station, + struct sk_buff *skb); extern void llc_station_send_pdu(struct llc_station *station, struct sk_buff *skb); extern struct sk_buff *llc_alloc_frame(void); diff --git a/include/net/llc_pdu.h b/include/net/llc_pdu.h index 6236c0cab669..02145e59174c 100644 --- a/include/net/llc_pdu.h +++ b/include/net/llc_pdu.h @@ -237,35 +237,35 @@ struct llc_frmr_info { extern void llc_pdu_set_cmd_rsp(struct sk_buff *skb, u8 type); extern void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value); -extern int llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit); -extern int llc_pdu_decode_cr_bit(struct sk_buff *skb, u8 *cr_bit); -extern int llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa); -extern int llc_pdu_decode_da(struct sk_buff *skb, u8 *ds); -extern int llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap); -extern int llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap); -extern int llc_decode_pdu_type(struct sk_buff *skb, u8 *destination); +extern void llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit); +extern void llc_pdu_decode_cr_bit(struct sk_buff *skb, u8 *cr_bit); +extern void llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa); +extern void llc_pdu_decode_da(struct sk_buff *skb, u8 *ds); +extern void llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap); +extern void llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap); +extern void llc_decode_pdu_type(struct sk_buff *skb, u8 *destination); extern void llc_pdu_header_init(struct sk_buff *skb, u8 pdu_type, u8 ssap, u8 dsap, u8 cr); -extern int llc_pdu_init_as_ui_cmd(struct sk_buff *skb); -extern int llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported, +extern void llc_pdu_init_as_ui_cmd(struct sk_buff *skb); +extern void llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported, u8 rx_window); -extern int llc_pdu_init_as_test_cmd(struct sk_buff *skb); -extern int llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit); -extern int llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr); -extern int llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr); -extern int llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr); -extern int llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr); -extern int llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit); -extern int llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit); -extern int llc_pdu_init_as_xid_rsp(struct sk_buff *skb, u8 svcs_supported, - u8 rx_window); -extern int llc_pdu_init_as_test_rsp(struct sk_buff *skb, - struct sk_buff *ev_skb); -extern int llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, - struct llc_pdu_sn *prev_pdu, - u8 f_bit, u8 vs, u8 vr, u8 vzyxw); -extern int llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr); -extern int llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr); -extern int llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr); -extern int llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit); +extern void llc_pdu_init_as_test_cmd(struct sk_buff *skb); +extern void llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit); +extern void llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr); +extern void llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr); +extern void llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr); +extern void llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr); +extern void llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit); +extern void llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit); +extern void llc_pdu_init_as_xid_rsp(struct sk_buff *skb, u8 svcs_supported, + u8 rx_window); +extern void llc_pdu_init_as_test_rsp(struct sk_buff *skb, + struct sk_buff *ev_skb); +extern void llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, + struct llc_pdu_sn *prev_pdu, + u8 f_bit, u8 vs, u8 vr, u8 vzyxw); +extern void llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr); +extern void llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr); +extern void llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr); +extern void llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit); #endif /* LLC_PDU_H */ diff --git a/include/net/llc_sap.h b/include/net/llc_sap.h index 3fd694a166e6..3132bebd1422 100644 --- a/include/net/llc_sap.h +++ b/include/net/llc_sap.h @@ -18,7 +18,6 @@ * @p_bit - only lowest-order bit used * @f_bit - only lowest-order bit used * @req - provided by LLC layer - * @resp - provided by LLC layer * @ind - provided by network layer * @conf - provided by network layer * @laddr - SAP value in this 'lsap' @@ -32,7 +31,6 @@ struct llc_sap { u8 p_bit; u8 f_bit; llc_prim_call_t req; - llc_prim_call_t resp; llc_prim_call_t ind; llc_prim_call_t conf; struct llc_prim_if_block llc_ind_prim, llc_cfm_prim; @@ -49,7 +47,7 @@ struct llc_sap_state_ev; extern void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk); extern void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk); -extern void llc_sap_send_ev(struct llc_sap *sap, struct sk_buff *skb); +extern void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb); extern void llc_sap_rtn_pdu(struct llc_sap *sap, struct sk_buff *skb); extern void llc_sap_send_pdu(struct llc_sap *sap, struct sk_buff *skb); #endif /* LLC_SAP_H */ diff --git a/net/8021q/vlan.c b/net/8021q/vlan.c index 7f15168db0c3..6f21903b0932 100644 --- a/net/8021q/vlan.c +++ b/net/8021q/vlan.c @@ -626,7 +626,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event, ret = unregister_vlan_dev(dev, VLAN_DEV_INFO(vlandev)->vlan_id); - unregister_netdev(vlandev); + unregister_netdevice(vlandev); /* Group was destroyed? */ if (ret == 1) diff --git a/net/core/dev.c b/net/core/dev.c index e67776f3a9ba..be5f1c87d480 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -694,10 +694,14 @@ int dev_open(struct net_device *dev) * Call device private open method */ if (try_inc_mod_count(dev->owner)) { + set_bit(__LINK_STATE_START, &dev->state); if (dev->open) { ret = dev->open(dev); - if (ret && dev->owner) - __MOD_DEC_USE_COUNT(dev->owner); + if (ret) { + clear_bit(__LINK_STATE_START, &dev->state); + if (dev->owner) + __MOD_DEC_USE_COUNT(dev->owner); + } } } else { ret = -ENODEV; @@ -713,8 +717,6 @@ int dev_open(struct net_device *dev) */ dev->flags |= IFF_UP; - set_bit(__LINK_STATE_START, &dev->state); - /* * Initialize multicasting status */ diff --git a/net/ipv4/ip_options.c b/net/ipv4/ip_options.c index 8faded2b254f..915da9809100 100644 --- a/net/ipv4/ip_options.c +++ b/net/ipv4/ip_options.c @@ -266,7 +266,7 @@ int ip_options_compile(struct ip_options * opt, struct sk_buff * skb) for (l = opt->optlen; l > 0; ) { switch (*optptr) { case IPOPT_END: - for (optptr++, l--; l>0; l--) { + for (optptr++, l--; l>0; optptr++, l--) { if (*optptr != IPOPT_END) { *optptr = IPOPT_END; opt->is_changed = 1; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index 7072ab51cf27..8c1d316db7b5 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -3289,17 +3289,24 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, if ((s32)(tp->rcv_tsval - tp->ts_recent) < 0) goto slow_path; - /* Predicted packet is in window by definition. - * seq == rcv_nxt and rcv_wup <= rcv_nxt. - * Hence, check seq<=rcv_wup reduces to: + /* DO NOT update ts_recent here, if checksum fails + * and timestamp was corrupted part, it will result + * in a hung connection since we will drop all + * future packets due to the PAWS test. */ - if (tp->rcv_nxt == tp->rcv_wup) - tcp_store_ts_recent(tp); } if (len <= tcp_header_len) { /* Bulk data transfer: sender */ if (len == tcp_header_len) { + /* Predicted packet is in window by definition. + * seq == rcv_nxt and rcv_wup <= rcv_nxt. + * Hence, check seq<=rcv_wup reduces to: + */ + if (tcp_header_len == + (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) && + tp->rcv_nxt == tp->rcv_wup) + tcp_store_ts_recent(tp); /* We know that such packets are checksummed * on entry. */ @@ -3325,12 +3332,30 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb, tp->rcv_nxt = TCP_SKB_CB(skb)->end_seq; NET_INC_STATS_BH(TCPHPHitsToUser); eaten = 1; + /* Predicted packet is in window by definition. + * seq == rcv_nxt and rcv_wup <= rcv_nxt. + * Hence, check seq<=rcv_wup reduces to: + */ + if (tcp_header_len == + (sizeof(struct tcphdr) + + TCPOLEN_TSTAMP_ALIGNED) && + tp->rcv_nxt == tp->rcv_wup) + tcp_store_ts_recent(tp); } } if (!eaten) { if (tcp_checksum_complete_user(sk, skb)) goto csum_error; + /* Predicted packet is in window by definition. + * seq == rcv_nxt and rcv_wup <= rcv_nxt. + * Hence, check seq<=rcv_wup reduces to: + */ + if (tcp_header_len == + (sizeof(struct tcphdr) + TCPOLEN_TSTAMP_ALIGNED) && + tp->rcv_nxt == tp->rcv_wup) + tcp_store_ts_recent(tp); + if ((int)skb->truesize > sk->forward_alloc) goto step5; diff --git a/net/llc/llc_actn.c b/net/llc/llc_actn.c index 4b63a130b0c9..dadb22054749 100644 --- a/net/llc/llc_actn.c +++ b/net/llc/llc_actn.c @@ -134,7 +134,7 @@ int llc_station_ac_report_status(struct llc_station *station, static void llc_station_ack_tmr_callback(unsigned long timeout_data) { struct llc_station *station = (struct llc_station *)timeout_data; - struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC); + struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); station->ack_tmr_running = 0; if (skb) { @@ -142,6 +142,6 @@ static void llc_station_ack_tmr_callback(unsigned long timeout_data) ev->type = LLC_STATION_EV_TYPE_ACK_TMR; ev->data.tmr.timer_specific = NULL; - llc_station_send_ev(station, skb); + llc_station_state_process(station, skb); } } diff --git a/net/llc/llc_c_ac.c b/net/llc/llc_c_ac.c index 96e61732c317..88a3c2f7e6be 100644 --- a/net/llc/llc_c_ac.c +++ b/net/llc/llc_c_ac.c @@ -65,24 +65,14 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb) sap = llc_sap_find(dsap); if (sap) { struct llc_conn_state_ev *ev = llc_conn_ev(skb); - struct llc_prim_if_block *prim = &sap->llc_ind_prim; - union llc_u_prim_data *prim_data = prim->data; struct llc_opt *llc = llc_sk(sk); - prim_data->conn.daddr.lsap = dsap; llc_pdu_decode_sa(skb, llc->daddr.mac); llc_pdu_decode_da(skb, llc->laddr.mac); llc->dev = skb->dev; - prim_data->conn.pri = 0; - prim_data->conn.sk = sk; - prim_data->conn.dev = skb->dev; - memcpy(&prim_data->conn.daddr, &llc->laddr, sizeof(llc->laddr)); - memcpy(&prim_data->conn.saddr, &llc->daddr, sizeof(llc->daddr)); - prim->data = prim_data; - prim->prim = LLC_CONN_PRIM; - prim->sap = llc->sap; - ev->flag = 1; - ev->ind_prim = prim; + /* FIXME: find better way to notify upper layer */ + ev->flag = LLC_CONN_PRIM + 1; + ev->ind_prim = (void *)1; rc = 0; } return rc; @@ -91,42 +81,22 @@ int llc_conn_ac_conn_ind(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_conn_confirm(struct sock *sk, struct sk_buff *skb) { struct llc_conn_state_ev *ev = llc_conn_ev(skb); - struct llc_opt *llc = llc_sk(sk); - struct llc_sap *sap = llc->sap; - struct llc_prim_if_block *prim = &sap->llc_cfm_prim; - union llc_u_prim_data *prim_data = prim->data; - prim_data->conn.sk = sk; - prim_data->conn.pri = 0; - prim_data->conn.status = ev->status; - prim_data->conn.link = llc->link; - prim_data->conn.dev = skb->dev; - prim->data = prim_data; - prim->prim = LLC_CONN_PRIM; - prim->sap = sap; - ev->flag = 1; - ev->cfm_prim = prim; + ev->flag = LLC_CONN_PRIM + 1; + ev->cfm_prim = (void *)1; return 0; } static int llc_conn_ac_data_confirm(struct sock *sk, struct sk_buff *skb) { struct llc_conn_state_ev *ev = llc_conn_ev(skb); - struct llc_opt *llc = llc_sk(sk); - struct llc_sap *sap = llc->sap; - struct llc_prim_if_block *prim = &sap->llc_cfm_prim; - union llc_u_prim_data *prim_data = prim->data; - prim_data->data.sk = sk; - prim_data->data.pri = 0; - prim_data->data.link = llc->link; - prim_data->data.status = LLC_STATUS_RECEIVED; - prim_data->data.skb = NULL; - prim->data = prim_data; - prim->prim = LLC_DATA_PRIM; - prim->sap = sap; - ev->flag = 1; - ev->cfm_prim = prim; + /* + * FIXME: find better way to tell upper layer that the packet was + * confirmed by the other endpoint + */ + ev->flag = LLC_DATA_PRIM + 1; + ev->cfm_prim = (void *)1; return 0; } @@ -164,19 +134,15 @@ int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb) rc = 1; } if (!rc) { - struct llc_opt *llc = llc_sk(sk); - struct llc_sap *sap = llc->sap; - struct llc_prim_if_block *prim = &sap->llc_ind_prim; - union llc_u_prim_data *prim_data = prim->data; - - prim_data->disc.sk = sk; - prim_data->disc.reason = reason; - prim_data->disc.link = llc->link; - prim->data = prim_data; - prim->prim = LLC_DISC_PRIM; - prim->sap = llc->sap; - ev->flag = 1; - ev->ind_prim = prim; + /* + * FIXME: ev needs reason field, + * perhaps the ev->status is enough, + * have to check, + * better way to signal its a disc + */ + /* prim_data->disc.reason = reason; */ + ev->flag = LLC_DISC_PRIM + 1; + ev->ind_prim = (void *)1; } return rc; } @@ -184,19 +150,11 @@ int llc_conn_ac_disc_ind(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_disc_confirm(struct sock *sk, struct sk_buff *skb) { struct llc_conn_state_ev *ev = llc_conn_ev(skb); - struct llc_opt *llc = llc_sk(sk); - struct llc_sap *sap = llc->sap; - struct llc_prim_if_block *prim = &sap->llc_cfm_prim; - union llc_u_prim_data *prim_data = prim->data; - prim_data->disc.sk = sk; - prim_data->disc.reason = ev->status; - prim_data->disc.link = llc->link; - prim->data = prim_data; - prim->prim = LLC_DISC_PRIM; - prim->sap = sap; - ev->flag = 1; - ev->cfm_prim = prim; + /* here we use the ev->status, humm */ + /* prim_data->disc.reason = ev->status; */ + ev->flag = LLC_DISC_PRIM + 1; + ev->cfm_prim = (void *)1; return 0; } @@ -1342,12 +1300,15 @@ int llc_conn_ac_upd_nr_received(struct sock *sk, struct sk_buff *skb) int llc_conn_ac_upd_p_flag(struct sock *sk, struct sk_buff *skb) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - u8 f_bit; - if (!LLC_PDU_IS_RSP(pdu) && - !llc_pdu_decode_pf_bit(skb, &f_bit) && f_bit) { - llc_sk(sk)->p_flag = 0; - llc_conn_ac_stop_p_timer(sk, skb); + if (!LLC_PDU_IS_RSP(pdu)) { + u8 f_bit; + + llc_pdu_decode_pf_bit(skb, &f_bit); + if (f_bit) { + llc_sk(sk)->p_flag = 0; + llc_conn_ac_stop_p_timer(sk, skb); + } } return 0; } @@ -1459,61 +1420,73 @@ int llc_conn_ac_set_f_flag_p(struct sock *sk, struct sk_buff *skb) void llc_conn_pf_cycle_tmr_cb(unsigned long timeout_data) { struct sock *sk = (struct sock *)timeout_data; - struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC); + struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); + bh_lock_sock(sk); llc_sk(sk)->pf_cycle_timer.running = 0; if (skb) { struct llc_conn_state_ev *ev = llc_conn_ev(skb); + skb->sk = sk; ev->type = LLC_CONN_EV_TYPE_P_TMR; ev->data.tmr.timer_specific = NULL; llc_process_tmr_ev(sk, skb); } + bh_unlock_sock(sk); } static void llc_conn_busy_tmr_cb(unsigned long timeout_data) { struct sock *sk = (struct sock *)timeout_data; - struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC); + struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); + bh_lock_sock(sk); llc_sk(sk)->busy_state_timer.running = 0; if (skb) { struct llc_conn_state_ev *ev = llc_conn_ev(skb); + skb->sk = sk; ev->type = LLC_CONN_EV_TYPE_BUSY_TMR; ev->data.tmr.timer_specific = NULL; llc_process_tmr_ev(sk, skb); } + bh_unlock_sock(sk); } void llc_conn_ack_tmr_cb(unsigned long timeout_data) { struct sock* sk = (struct sock *)timeout_data; - struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC); + struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); + bh_lock_sock(sk); llc_sk(sk)->ack_timer.running = 0; if (skb) { struct llc_conn_state_ev *ev = llc_conn_ev(skb); + skb->sk = sk; ev->type = LLC_CONN_EV_TYPE_ACK_TMR; ev->data.tmr.timer_specific = NULL; llc_process_tmr_ev(sk, skb); } + bh_unlock_sock(sk); } static void llc_conn_rej_tmr_cb(unsigned long timeout_data) { struct sock *sk = (struct sock *)timeout_data; - struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC); + struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); + bh_lock_sock(sk); llc_sk(sk)->rej_sent_timer.running = 0; if (skb) { struct llc_conn_state_ev *ev = llc_conn_ev(skb); + skb->sk = sk; ev->type = LLC_CONN_EV_TYPE_REJ_TMR; ev->data.tmr.timer_specific = NULL; llc_process_tmr_ev(sk, skb); } + bh_unlock_sock(sk); } int llc_conn_ac_rst_vs(struct sock *sk, struct sk_buff *skb) @@ -1541,14 +1514,11 @@ int llc_conn_ac_upd_vs(struct sock *sk, struct sk_buff *skb) * llc_conn_disc - removes connection from SAP list and frees it * @sk: closed connection * @skb: occurred event - * - * Returns 2, to indicate the state machine that the connection was freed. */ int llc_conn_disc(struct sock *sk, struct sk_buff *skb) { - llc_sap_unassign_sock(llc_sk(sk)->sap, sk); - llc_sock_free(sk); - return 2; + /* FIXME: this thing seems to want to die */ + return 0; } /** @@ -1560,7 +1530,7 @@ int llc_conn_disc(struct sock *sk, struct sk_buff *skb) */ int llc_conn_reset(struct sock *sk, struct sk_buff *skb) { - llc_sock_reset(sk); + llc_sk_reset(sk); return 0; } @@ -1589,24 +1559,21 @@ u8 llc_circular_between(u8 a, u8 b, u8 c) * This function is called from timer callback functions. When connection * is busy (during sending a data frame) timer expiration event must be * queued. Otherwise this event can be sent to connection state machine. - * Queued events will process by process_rxframes_events function after - * sending data frame. Returns 0 for success, 1 otherwise. + * Queued events will process by llc_backlog_rcv function after sending + * data frame. */ static void llc_process_tmr_ev(struct sock *sk, struct sk_buff *skb) { - bh_lock_sock(sk); if (llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) { printk(KERN_WARNING "%s: timer called on closed connection\n", __FUNCTION__); llc_conn_free_ev(skb); - goto out; - } - if (!sk->lock.users) - llc_conn_send_ev(sk, skb); - else { - llc_set_backlog_type(skb, LLC_EVENT); - sk_add_backlog(sk, skb); + } else { + if (!sk->lock.users) + llc_conn_state_process(sk, skb); + else { + llc_set_backlog_type(skb, LLC_EVENT); + sk_add_backlog(sk, skb); + } } -out: - bh_unlock_sock(sk); } diff --git a/net/llc/llc_c_ev.c b/net/llc/llc_c_ev.c index e300584ac8f8..9b455714143a 100644 --- a/net/llc/llc_c_ev.c +++ b/net/llc/llc_c_ev.c @@ -241,9 +241,8 @@ int llc_conn_ev_rx_i_cmd_pbit_set_x_inval_ns(struct sock *sk, u16 rc = !LLC_PDU_IS_CMD(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr && llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; if (!rc) - dprintk(KERN_WARNING "rx_i_cmd_p_bit_set_x_inval_ns matched," - "state = %d, ns = %d, vr = %d\n", - llc_sk(sk)->state, ns, vr); + dprintk("%s: matched, state=%d, ns=%d, vr=%d\n", + __FUNCTION__, llc_sk(sk)->state, ns, vr); return rc; } @@ -317,9 +316,8 @@ int llc_conn_ev_rx_i_rsp_fbit_set_x_inval_ns(struct sock *sk, u16 rc = !LLC_PDU_IS_RSP(pdu) && !LLC_PDU_TYPE_IS_I(pdu) && ns != vr && llc_util_ns_inside_rx_window(ns, vr, llc_sk(sk)->rw) ? 0 : 1; if (!rc) - dprintk(KERN_WARNING "conn_ev_rx_i_rsp_fbit_set_x_inval_ns " - "matched : state = %d, ns = %d, vr = %d\n", - llc_sk(sk)->state, ns, vr); + dprintk("%s: matched, state=%d, ns=%d, vr=%d\n", + __FUNCTION__, llc_sk(sk)->state, ns, vr); return rc; } @@ -584,9 +582,8 @@ int llc_conn_ev_rx_zzz_cmd_pbit_set_x_inval_nr(struct sock *sk, if (!LLC_PDU_IS_CMD(pdu) && (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) && nr != vs && llc_util_nr_inside_tx_window(sk, nr)) { - dprintk(KERN_ERR "conn_ev_rx_zzz_cmd_inv_nr matched, state = " - "%d, vs = %d, nr = %d\n", - llc_sk(sk)->state, vs, nr); + dprintk("%s: matched, state=%d, vs=%d, nr=%d\n", + __FUNCTION__, llc_sk(sk)->state, vs, nr); rc = 0; } return rc; @@ -604,9 +601,8 @@ int llc_conn_ev_rx_zzz_rsp_fbit_set_x_inval_nr(struct sock *sk, (!LLC_PDU_TYPE_IS_I(pdu) || !LLC_PDU_TYPE_IS_S(pdu)) && nr != vs && llc_util_nr_inside_tx_window(sk, nr)) { rc = 0; - dprintk(KERN_ERR "conn_ev_rx_zzz_fbit_set_x_inval_nr matched, " - "state = %d, vs = %d, nr = %d\n", - llc_sk(sk)->state, vs, nr); + dprintk("%s: matched, state=%d, vs=%d, nr=%d\n", + __FUNCTION__, llc_sk(sk)->state, vs, nr); } return rc; } diff --git a/net/llc/llc_conn.c b/net/llc/llc_conn.c index 98072a6c552d..377887a246e4 100644 --- a/net/llc/llc_conn.c +++ b/net/llc/llc_conn.c @@ -18,6 +18,7 @@ #include <net/llc_sap.h> #include <net/llc_conn.h> #include <net/sock.h> +#include <linux/tcp.h> #include <net/llc_main.h> #include <net/llc_c_ev.h> #include <net/llc_c_ac.h> @@ -38,65 +39,149 @@ static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk, /* Offset table on connection states transition diagram */ static int llc_offset_table[NBR_CONN_STATES][NBR_CONN_EV]; +static void llc_save_primitive(struct sock *sk, struct sk_buff* skb, + u8 ua, u8 test, u8 xid) +{ + struct llc_opt *llc = llc_sk(sk); + struct sockaddr_llc *addr = llc_ui_skb_cb(skb); + + /* save primitive for use by the user. */ + addr->sllc_family = sk->family; + addr->sllc_arphrd = skb->dev->type; + addr->sllc_test = test; + addr->sllc_xid = xid; + addr->sllc_ua = ua; + addr->sllc_dsap = llc->sap->laddr.lsap; + memcpy(addr->sllc_dmac, llc->laddr.mac, IFHWADDRLEN); + addr->sllc_ssap = llc->daddr.lsap; + memcpy(addr->sllc_smac, llc->daddr.mac, IFHWADDRLEN); +} + /** - * llc_conn_send_event - sends event to connection state machine + * llc_conn_state_process - sends event to connection state machine * @sk: connection * @skb: occurred event * - * Sends an event to connection state machine. after processing event + * Sends an event to connection state machine. After processing event * (executing it's actions and changing state), upper layer will be * indicated or confirmed, if needed. Returns 0 for success, 1 for * failure. The socket lock has to be held before calling this function. */ -int llc_conn_send_ev(struct sock *sk, struct sk_buff *skb) +int llc_conn_state_process(struct sock *sk, struct sk_buff *skb) { /* sending event to state machine */ int rc = llc_conn_service(sk, skb); struct llc_opt *llc = llc_sk(sk); struct llc_conn_state_ev *ev = llc_conn_ev(skb); u8 flag = ev->flag; + u8 status = ev->status; struct llc_prim_if_block *ind_prim = ev->ind_prim; struct llc_prim_if_block *cfm_prim = ev->cfm_prim; - llc_conn_free_ev(skb); -#ifdef THIS_BREAKS_DISCONNECT_NOTIFICATION_BADLY - /* check if the connection was freed by the state machine by - * means of llc_conn_disc */ - if (rc == 2) { - printk(KERN_INFO "%s: rc == 2\n", __FUNCTION__); - rc = -ECONNABORTED; - goto out; - } -#endif /* THIS_BREAKS_DISCONNECT_NOTIFICATION_BADLY */ + /* + * FIXME: this will vanish as soon I get rid of the last prim crap + */ + if (flag != LLC_DATA_PRIM + 1 && flag != LLC_CONN_PRIM + 1 && + flag != LLC_DISC_PRIM + 1) + llc_conn_free_ev(skb); + else if (ind_prim && cfm_prim) + skb_get(skb); if (!flag) /* indicate or confirm not required */ goto out; rc = 0; - if (ind_prim) /* indication required */ - llc->sap->ind(ind_prim); + if (ind_prim) { /* indication required */ + /* + * FIXME: this will be saner as soon I get rid of the double + * sock crap + */ + switch (flag) { + case LLC_DATA_PRIM + 1: + llc_save_primitive(sk, skb, 0, 0, 0); + if (sock_queue_rcv_skb(sk, skb)) { + /* + * FIXME: have to sync the LLC state + * machine wrt mem usage with + * sk->{r,w}mem_alloc, will do + * this soon 8) + */ + printk(KERN_ERR + "%s: sock_queue_rcv_skb failed!\n", + __FUNCTION__); + kfree_skb(skb); + } + break; + case LLC_CONN_PRIM + 1: { + struct sock *parent = skb->sk; + + skb->sk = sk; + skb_queue_tail(&parent->receive_queue, skb); + sk->state_change(parent); + } + break; + case LLC_DISC_PRIM + 1: + sock_hold(sk); + if (sk->type == SOCK_STREAM && sk->state == TCP_ESTABLISHED) { + sk->shutdown = SHUTDOWN_MASK; + sk->socket->state = SS_UNCONNECTED; + sk->state = TCP_CLOSE; + if (!sk->dead) { + sk->state_change(sk); + sk->dead = 1; + } + } + kfree_skb(skb); + sock_put(sk); + break; + default: + llc->sap->ind(ind_prim); + } + } if (!cfm_prim) /* confirmation not required */ goto out; - /* data confirm has preconditions */ - if (cfm_prim->prim != LLC_DATA_PRIM) { + /* FIXME: see FIXMEs above */ + switch (flag) { + case LLC_DATA_PRIM + 1: + if (!llc_data_accept_state(llc->state)) + /* In this state, we can send I pdu */ + sk->write_space(sk); + else + rc = llc->failed_data_req = 1; + break; + case LLC_CONN_PRIM + 1: + if (sk->type != SOCK_STREAM || sk->state != TCP_SYN_SENT) + goto out_kfree_skb; + if (status) { + sk->socket->state = SS_UNCONNECTED; + sk->state = TCP_CLOSE; + } else { + sk->socket->state = SS_CONNECTED; + sk->state = TCP_ESTABLISHED; + } + sk->state_change(sk); + break; + case LLC_DISC_PRIM + 1: + sock_hold(sk); + if (sk->type != SOCK_STREAM || sk->state != TCP_CLOSING) { + sock_put(sk); + goto out_kfree_skb; + } + sk->socket->state = SS_UNCONNECTED; + sk->state = TCP_CLOSE; + sk->state_change(sk); + sock_put(sk); + break; + default: llc->sap->conf(cfm_prim); goto out; } - if (!llc_data_accept_state(llc->state)) { - /* In this state, we can send I pdu */ - /* FIXME: check if we don't need to see if sk->lock.users != 0 - * is needed here - */ - rc = llc->sap->conf(cfm_prim); - if (rc) /* confirmation didn't accept by upper layer */ - llc->failed_data_req = 1; - } else - llc->failed_data_req = 1; +out_kfree_skb: + kfree_skb(skb); out: return rc; } void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb) { - llc_sock_assert(sk); /* queue PDU to send to MAC layer */ skb_queue_tail(&sk->write_queue, skb); llc_conn_send_pdus(sk); @@ -109,26 +194,15 @@ void llc_conn_send_pdu(struct sock *sk, struct sk_buff *skb) * * Sends received data pdu to upper layer (by using indicate function). * Prepares service parameters (prim and prim_data). calling indication - * function will be done in llc_conn_send_ev. + * function will be done in llc_conn_state_process. */ void llc_conn_rtn_pdu(struct sock *sk, struct sk_buff *skb) { struct llc_conn_state_ev *ev = llc_conn_ev(skb); - struct llc_opt *llc = llc_sk(sk); - struct llc_sap *sap = llc->sap; - struct llc_prim_if_block *prim = &sap->llc_ind_prim; - union llc_u_prim_data *prim_data = prim->data; - - prim_data->data.sk = sk; - prim_data->data.pri = 0; - prim_data->data.skb = skb; - prim_data->data.link = llc->link; - prim->data = prim_data; - prim->prim = LLC_DATA_PRIM; - prim->sap = sap; - ev->flag = 1; - /* saving prepd prim in event for future use in llc_conn_send_ev */ - ev->ind_prim = prim; + + /* FIXME: indicate that we should send this to the upper layer */ + ev->flag = LLC_DATA_PRIM + 1; + ev->ind_prim = (void *)1; } /** @@ -369,11 +443,10 @@ static struct llc_conn_state_trans *llc_qualify_conn_ev(struct sock *sk, * llc_exec_conn_trans_actions - executes related actions * @sk: connection * @trans: transition that it's actions must be performed - * @skb: happened event + * @skb: event * * Executes actions that is related to happened event. Returns 0 for - * success, 1 to indicate failure of at least one action or 2 if the - * connection was freed (llc_conn_disc was called) + * success, 1 to indicate failure of at least one action. */ static int llc_exec_conn_trans_actions(struct sock *sk, struct llc_conn_state_trans *trans, @@ -396,7 +469,7 @@ static int llc_exec_conn_trans_actions(struct sock *sk, } /** - * llc_find_sock - Finds connection in sap for the remote/local sap/mac + * llc_lookup_established - Finds connection for the remote/local sap/mac * @sap: SAP * @daddr: address of remote LLC (MAC + SAP) * @laddr: address of local LLC (MAC + SAP) @@ -405,8 +478,8 @@ static int llc_exec_conn_trans_actions(struct sock *sk, * mac, remote sap, local mac, and local sap. Returns pointer for * connection found, %NULL otherwise. */ -struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr, - struct llc_addr *laddr) +struct sock *llc_lookup_established(struct llc_sap *sap, struct llc_addr *daddr, + struct llc_addr *laddr) { struct sock *rc = NULL; struct list_head *entry; @@ -419,8 +492,8 @@ struct sock *llc_find_sock(struct llc_sap *sap, struct llc_addr *daddr, if (llc->laddr.lsap == laddr->lsap && llc->daddr.lsap == daddr->lsap && - !memcmp(llc->laddr.mac, laddr->mac, ETH_ALEN) && - !memcmp(llc->daddr.mac, daddr->mac, ETH_ALEN)) { + llc_mac_match(llc->laddr.mac, laddr->mac) && + llc_mac_match(llc->daddr.mac, daddr->mac)) { rc = llc->sk; break; } @@ -433,6 +506,39 @@ out: } /** + * llc_lookup_listener - Finds listener for local MAC + SAP + * @sap: SAP + * @laddr: address of local LLC (MAC + SAP) + * + * Search connection list of the SAP and finds connection listening on + * local mac, and local sap. Returns pointer for parent socket found, + * %NULL otherwise. + */ +struct sock *llc_lookup_listener(struct llc_sap *sap, struct llc_addr *laddr) +{ + struct sock *rc = NULL; + struct list_head *entry; + + spin_lock_bh(&sap->sk_list.lock); + if (list_empty(&sap->sk_list.list)) + goto out; + list_for_each(entry, &sap->sk_list.list) { + struct llc_opt *llc = list_entry(entry, struct llc_opt, node); + + if (llc->sk->type != SOCK_STREAM || llc->sk->state != TCP_LISTEN || + llc->laddr.lsap != laddr->lsap || + !llc_mac_match(llc->laddr.mac, laddr->mac)) + continue; + rc = llc->sk; + } + if (rc) + sock_hold(rc); +out: + spin_unlock_bh(&sap->sk_list.lock); + return rc; +} + +/** * llc_data_accept_state - designates if in this state data can be sent. * @state: state of connection. * @@ -440,10 +546,8 @@ out: */ u8 llc_data_accept_state(u8 state) { - if (state != LLC_CONN_STATE_NORMAL && state != LLC_CONN_STATE_BUSY && - state != LLC_CONN_STATE_REJ) - return 1; /* data_conn_refuse */ - return 0; + return state != LLC_CONN_STATE_NORMAL && state != LLC_CONN_STATE_BUSY && + state != LLC_CONN_STATE_REJ; } /** diff --git a/net/llc/llc_if.c b/net/llc/llc_if.c index a53cc174adf0..393173d91156 100644 --- a/net/llc/llc_if.c +++ b/net/llc/llc_if.c @@ -15,6 +15,7 @@ #include <linux/module.h> #include <linux/kernel.h> #include <linux/netdevice.h> +#include <linux/tcp.h> #include <asm/errno.h> #include <net/llc_if.h> #include <net/llc_sap.h> @@ -27,42 +28,6 @@ #include <net/llc_main.h> #include <net/llc_mac.h> -static int llc_sap_req(struct llc_prim_if_block *prim); -static int llc_unitdata_req_handler(struct llc_prim_if_block *prim); -static int llc_test_req_handler(struct llc_prim_if_block *prim); -static int llc_xid_req_handler(struct llc_prim_if_block *prim); -static int llc_data_req_handler(struct llc_prim_if_block *prim); -static int llc_conn_req_handler(struct llc_prim_if_block *prim); -static int llc_disc_req_handler(struct llc_prim_if_block *prim); -static int llc_rst_req_handler(struct llc_prim_if_block *prim); -static int llc_flowcontrol_req_handler(struct llc_prim_if_block *prim); -static int llc_sap_resp(struct llc_prim_if_block *prim); -static int llc_conn_rsp_handler(struct llc_prim_if_block *prim); -static int llc_rst_rsp_handler(struct llc_prim_if_block *prim); -static int llc_no_rsp_handler(struct llc_prim_if_block *prim); - -/* table of request handler functions */ -static llc_prim_call_t llc_req_prim[LLC_NBR_PRIMITIVES] = { - [LLC_DATAUNIT_PRIM] = llc_unitdata_req_handler, - [LLC_CONN_PRIM] = llc_conn_req_handler, - [LLC_DATA_PRIM] = llc_data_req_handler, - [LLC_DISC_PRIM] = llc_disc_req_handler, - [LLC_RESET_PRIM] = llc_rst_req_handler, - [LLC_FLOWCONTROL_PRIM] = llc_flowcontrol_req_handler, - [LLC_XID_PRIM] = llc_xid_req_handler, - [LLC_TEST_PRIM] = llc_test_req_handler, -}; - -/* table of response handler functions */ -static llc_prim_call_t llc_resp_prim[LLC_NBR_PRIMITIVES] = { - [LLC_DATAUNIT_PRIM] = llc_no_rsp_handler, - [LLC_CONN_PRIM] = llc_conn_rsp_handler, - [LLC_DATA_PRIM] = llc_no_rsp_handler, - [LLC_DISC_PRIM] = llc_no_rsp_handler, - [LLC_RESET_PRIM] = llc_rst_rsp_handler, - [LLC_FLOWCONTROL_PRIM] = llc_no_rsp_handler, -}; - /** * llc_sap_open - open interface to the upper layers. * @nw_indicate: pointer to indicate function of upper layer. @@ -70,7 +35,7 @@ static llc_prim_call_t llc_resp_prim[LLC_NBR_PRIMITIVES] = { * @lsap: SAP number. * @sap: pointer to allocated SAP (output argument). * - * Interface function to upper layer. each one who wants to get a SAP + * Interface function to upper layer. Each one who wants to get a SAP * (for example NetBEUI) should call this function. Returns the opened * SAP for success, NULL for failure. */ @@ -92,8 +57,6 @@ struct llc_sap *llc_sap_open(llc_prim_call_t nw_indicate, goto err; /* allocated a SAP; initialize it and clear out its memory pool */ sap->laddr.lsap = lsap; - sap->req = llc_sap_req; - sap->resp = llc_sap_resp; sap->ind = nw_indicate; sap->conf = nw_confirm; sap->parent_station = llc_station_get(); @@ -110,7 +73,7 @@ err: * llc_sap_close - close interface for upper layers. * @sap: SAP to be closed. * - * Close interface function to upper layer. each one who wants to + * Close interface function to upper layer. Each one who wants to * close an open SAP (for example NetBEUI) should call this function. */ void llc_sap_close(struct llc_sap *sap) @@ -120,142 +83,135 @@ void llc_sap_close(struct llc_sap *sap) } /** - * llc_sap_req - Request interface for upper layers - * @prim: pointer to structure that contains service parameters. + * llc_build_and_send_ui_pkt - unitdata request interface for upper layers + * @sap: sap to use + * @skb: packet to send + * @addr: destination address * - * Request interface function to upper layer. each one who wants to - * request a service from LLC, must call this function. details of - * requested service is defined in input argument(prim). Returns 0 for - * success, 1 otherwise. + * Upper layers calls this function when upper layer wants to send data + * using connection-less mode communication (UI pdu). + * + * Accept data frame from network layer to be sent using connection- + * less mode communication; timeout/retries handled by network layer; + * package primitive as an event and send to SAP event handler */ -static int llc_sap_req(struct llc_prim_if_block *prim) +void llc_build_and_send_ui_pkt(struct llc_sap *sap, + struct sk_buff *skb, + struct sockaddr_llc *addr) { - int rc = 1; + union llc_u_prim_data prim_data; + struct llc_prim_if_block prim; + struct llc_sap_state_ev *ev = llc_sap_ev(skb); - if (prim->prim > 8 || prim->prim == 6) { - printk(KERN_ERR "%s: invalid primitive %d\n", __FUNCTION__, - prim->prim); - goto out; - } - /* receive REQUEST primitive from network layer; call the appropriate - * primitive handler which then packages it up as an event and sends it - * to the SAP or CONNECTION event handler - */ - if (prim->prim < LLC_NBR_PRIMITIVES) - /* valid primitive; call the function to handle it */ - rc = llc_req_prim[prim->prim](prim); -out: - return rc; -} + skb->protocol = llc_proto_type(addr->sllc_arphrd); -/** - * llc_unitdata_req_handler - unitdata request interface for upper layers - * @prim: pointer to structure that contains service parameters - * - * Upper layers calls this function when upper layer wants to send data - * using connection-less mode communication (UI pdu). Returns 0 for - * success, 1 otherwise. - */ -static int llc_unitdata_req_handler(struct llc_prim_if_block *prim) -{ - int rc = 1; - struct llc_sap_state_ev *ev; - /* accept data frame from network layer to be sent using connection- - * less mode communication; timeout/retries handled by network layer; - * package primitive as an event and send to SAP event handler - */ - struct llc_sap *sap = llc_sap_find(prim->data->udata.saddr.lsap); + prim.data = &prim_data; + prim.sap = sap; + prim.prim = LLC_DATAUNIT_PRIM; + + prim_data.udata.skb = skb; + prim_data.udata.saddr.lsap = sap->laddr.lsap; + prim_data.udata.daddr.lsap = addr->sllc_dsap; + memcpy(prim_data.udata.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN); + memcpy(prim_data.udata.daddr.mac, addr->sllc_dmac, IFHWADDRLEN); - if (!sap) - goto out; - ev = llc_sap_ev(prim->data->udata.skb); ev->type = LLC_SAP_EV_TYPE_PRIM; ev->data.prim.prim = LLC_DATAUNIT_PRIM; ev->data.prim.type = LLC_PRIM_TYPE_REQ; - ev->data.prim.data = prim; - rc = 0; - llc_sap_send_ev(sap, prim->data->udata.skb); -out: - return rc; + ev->data.prim.data = &prim; + llc_sap_state_process(sap, skb); } /** - * llc_test_req_handler - TEST interface for upper layers. - * @prim: pointer to structure that contains service parameters. + * llc_build_and_send_test_pkt - TEST interface for upper layers. + * @sap: sap to use + * @skb: packet to send + * @addr: destination address * * This function is called when upper layer wants to send a TEST pdu. * Returns 0 for success, 1 otherwise. */ -static int llc_test_req_handler(struct llc_prim_if_block *prim) +void llc_build_and_send_test_pkt(struct llc_sap *sap, + struct sk_buff *skb, + struct sockaddr_llc *addr) { - int rc = 1; - struct llc_sap_state_ev *ev; - /* package primitive as an event and send to SAP event handler */ - struct llc_sap *sap = llc_sap_find(prim->data->udata.saddr.lsap); - if (!sap) - goto out; - ev = llc_sap_ev(prim->data->udata.skb); + union llc_u_prim_data prim_data; + struct llc_prim_if_block prim; + struct llc_sap_state_ev *ev = llc_sap_ev(skb); + + skb->protocol = llc_proto_type(addr->sllc_arphrd); + + prim.data = &prim_data; + prim.sap = sap; + prim.prim = LLC_TEST_PRIM; + + prim_data.test.skb = skb; + prim_data.test.saddr.lsap = sap->laddr.lsap; + prim_data.test.daddr.lsap = addr->sllc_dsap; + memcpy(prim_data.test.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN); + memcpy(prim_data.test.daddr.mac, addr->sllc_dmac, IFHWADDRLEN); + ev->type = LLC_SAP_EV_TYPE_PRIM; ev->data.prim.prim = LLC_TEST_PRIM; ev->data.prim.type = LLC_PRIM_TYPE_REQ; - ev->data.prim.data = prim; - rc = 0; - llc_sap_send_ev(sap, prim->data->udata.skb); -out: - return rc; + ev->data.prim.data = &prim; + llc_sap_state_process(sap, skb); } /** - * llc_xid_req_handler - XID interface for upper layers - * @prim: pointer to structure that contains service parameters. + * llc_build_and_send_xid_pkt - XID interface for upper layers + * @sap: sap to use + * @skb: packet to send + * @addr: destination address * * This function is called when upper layer wants to send a XID pdu. * Returns 0 for success, 1 otherwise. */ -static int llc_xid_req_handler(struct llc_prim_if_block *prim) +void llc_build_and_send_xid_pkt(struct llc_sap *sap, + struct sk_buff *skb, + struct sockaddr_llc *addr) { - int rc = 1; - struct llc_sap_state_ev *ev; - /* package primitive as an event and send to SAP event handler */ - struct llc_sap *sap = llc_sap_find(prim->data->udata.saddr.lsap); + union llc_u_prim_data prim_data; + struct llc_prim_if_block prim; + struct llc_sap_state_ev *ev = llc_sap_ev(skb); + + skb->protocol = llc_proto_type(addr->sllc_arphrd); + + prim.data = &prim_data; + prim.sap = sap; + prim.prim = LLC_XID_PRIM; + + prim_data.xid.skb = skb; + prim_data.xid.saddr.lsap = sap->laddr.lsap; + prim_data.xid.daddr.lsap = addr->sllc_dsap; + memcpy(prim_data.xid.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN); + memcpy(prim_data.xid.daddr.mac, addr->sllc_dmac, IFHWADDRLEN); - if (!sap) - goto out; - ev = llc_sap_ev(prim->data->udata.skb); ev->type = LLC_SAP_EV_TYPE_PRIM; ev->data.prim.prim = LLC_XID_PRIM; ev->data.prim.type = LLC_PRIM_TYPE_REQ; - ev->data.prim.data = prim; - rc = 0; - llc_sap_send_ev(sap, prim->data->udata.skb); -out: - return rc; + ev->data.prim.data = &prim; + llc_sap_state_process(sap, skb); } /** - * llc_data_req_handler - Connection data sending for upper layers. + * llc_build_and_send_pkt - Connection data sending for upper layers. * @prim: pointer to structure that contains service parameters * * This function is called when upper layer wants to send data using - * connection oriented communication mode. during sending data, connection + * connection oriented communication mode. During sending data, connection * will be locked and received frames and expired timers will be queued. * Returns 0 for success, -ECONNABORTED when the connection already - * closed. and -EBUSY when sending data is not permitted in this state or + * closed and -EBUSY when sending data is not permitted in this state or * LLC has send an I pdu with p bit set to 1 and is waiting for it's * response. */ -static int llc_data_req_handler(struct llc_prim_if_block *prim) +int llc_build_and_send_pkt(struct sock *sk, struct sk_buff *skb) { struct llc_conn_state_ev *ev; int rc = -ECONNABORTED; - /* accept data frame from network layer to be sent using connection - * mode communication; timeout/retries handled by this layer; - * package primitive as an event and send to connection event handler - */ - struct sock *sk = prim->data->data.sk; struct llc_opt *llc = llc_sk(sk); - lock_sock(sk); if (llc->state == LLC_CONN_STATE_ADM) goto out; rc = -EBUSY; @@ -267,169 +223,121 @@ static int llc_data_req_handler(struct llc_prim_if_block *prim) llc->failed_data_req = 1; goto out; } - ev = llc_conn_ev(prim->data->data.skb); - ev->type = LLC_CONN_EV_TYPE_PRIM; - ev->data.prim.prim = LLC_DATA_PRIM; - ev->data.prim.type = LLC_PRIM_TYPE_REQ; - ev->data.prim.data = prim; - prim->data->data.skb->dev = llc->dev; - rc = llc_conn_send_ev(sk, prim->data->data.skb); + ev = llc_conn_ev(skb); + ev->type = LLC_CONN_EV_TYPE_PRIM; + ev->data.prim.prim = LLC_DATA_PRIM; + ev->data.prim.type = LLC_PRIM_TYPE_REQ; + ev->data.prim.data = NULL; + skb->dev = llc->dev; + rc = llc_conn_state_process(sk, skb); out: - release_sock(sk); return rc; } /** - * llc_confirm_impossible - Informs upper layer about failed connection - * @prim: pointer to structure that contains confirmation data. - * - * Informs upper layer about failing in connection establishment. This - * function is called by llc_conn_req_handler. - */ -static void llc_confirm_impossible(struct llc_prim_if_block *prim) -{ - prim->data->conn.status = LLC_STATUS_IMPOSSIBLE; - prim->sap->conf(prim); -} - -/** - * llc_conn_req_handler - Called by upper layer to establish a conn - * @prim: pointer to structure that contains service parameters. + * llc_establish_connection - Called by upper layer to establish a conn + * @sk: connection + * @lmac: local mac address + * @dmac: destination mac address + * @dsap: destination sap * * Upper layer calls this to establish an LLC connection with a remote - * machine. this function packages a proper event and sends it connection - * component state machine. Success or failure of connection + * machine. This function packages a proper event and sends it connection + * component state machine. Success or failure of connection * establishment will inform to upper layer via calling it's confirm * function and passing proper information. */ -static int llc_conn_req_handler(struct llc_prim_if_block *prim) +int llc_establish_connection(struct sock *sk, u8 *lmac, u8 *dmac, u8 dsap) { - int rc = -EBUSY; - struct llc_opt *llc; - struct llc_sap *sap = prim->sap; - struct sk_buff *skb; - struct net_device *ddev = mac_dev_peer(prim->data->conn.dev, - prim->data->conn.dev->type, - prim->data->conn.daddr.mac), - *sdev = (ddev->flags & IFF_LOOPBACK) ? - ddev : prim->data->conn.dev; + int rc = -EISCONN; struct llc_addr laddr, daddr; - /* network layer supplies addressing required to establish connection; - * package as an event and send it to the connection event handler - */ - struct sock *sk; - - memcpy(laddr.mac, sdev->dev_addr, sizeof(laddr.mac)); - laddr.lsap = prim->data->conn.saddr.lsap; - memcpy(daddr.mac, prim->data->conn.daddr.mac, sizeof(daddr.mac)); - daddr.lsap = prim->data->conn.daddr.lsap; - sk = llc_find_sock(sap, &daddr, &laddr); - if (sk) { - llc_confirm_impossible(prim); - goto out_put; - } - rc = -ENOMEM; - if (prim->data->conn.sk) { - sk = prim->data->conn.sk; - if (llc_sock_init(sk)) - goto out; - } else { - sk = llc_sock_alloc(); - if (!sk) { - llc_confirm_impossible(prim); - goto out; - } - prim->data->conn.sk = sk; + struct sk_buff *skb; + struct llc_opt *llc = llc_sk(sk); + struct sock *existing; + + laddr.lsap = llc->sap->laddr.lsap; + daddr.lsap = dsap; + memcpy(daddr.mac, dmac, sizeof(daddr.mac)); + memcpy(laddr.mac, lmac, sizeof(laddr.mac)); + existing = llc_lookup_established(llc->sap, &daddr, &laddr); + if (existing) { + if (existing->state == TCP_ESTABLISHED) { + sk = existing; + goto out_put; + } else + sock_put(existing); } sock_hold(sk); - lock_sock(sk); - /* assign new connection to it's SAP */ - llc_sap_assign_sock(sap, sk); - llc = llc_sk(sk); - memcpy(&llc->daddr, &daddr, sizeof(llc->daddr)); - memcpy(&llc->laddr, &laddr, sizeof(llc->laddr)); - llc->dev = ddev; - llc->link = prim->data->conn.link; - llc->handler = prim->data->conn.handler; - skb = alloc_skb(1, GFP_ATOMIC); + rc = -ENOMEM; + skb = alloc_skb(0, GFP_ATOMIC); if (skb) { struct llc_conn_state_ev *ev = llc_conn_ev(skb); ev->type = LLC_CONN_EV_TYPE_PRIM; ev->data.prim.prim = LLC_CONN_PRIM; ev->data.prim.type = LLC_PRIM_TYPE_REQ; - ev->data.prim.data = prim; - rc = llc_conn_send_ev(sk, skb); - } - if (rc) { - llc_sap_unassign_sock(sap, sk); - llc_sock_free(sk); - llc_confirm_impossible(prim); + ev->data.prim.data = NULL; + rc = llc_conn_state_process(sk, skb); } - release_sock(sk); out_put: sock_put(sk); -out: return rc; } /** - * llc_disc_req_handler - Called by upper layer to close a connection - * @prim: pointer to structure that contains service parameters. + * llc_send_disc - Called by upper layer to close a connection + * @sk: connection to be closed * * Upper layer calls this when it wants to close an established LLC - * connection with a remote machine. this function packages a proper event + * connection with a remote machine. This function packages a proper event * and sends it to connection component state machine. Returns 0 for * success, 1 otherwise. */ -static int llc_disc_req_handler(struct llc_prim_if_block *prim) +int llc_send_disc(struct sock *sk) { u16 rc = 1; struct llc_conn_state_ev *ev; struct sk_buff *skb; - struct sock* sk = prim->data->disc.sk; sock_hold(sk); - lock_sock(sk); - if (llc_sk(sk)->state == LLC_CONN_STATE_ADM || + if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED || + llc_sk(sk)->state == LLC_CONN_STATE_ADM || llc_sk(sk)->state == LLC_CONN_OUT_OF_SVC) goto out; /* * Postpone unassigning the connection from its SAP and returning the * connection until all ACTIONs have been completely executed */ - skb = alloc_skb(1, GFP_ATOMIC); + skb = alloc_skb(0, GFP_ATOMIC); if (!skb) goto out; - ev = llc_conn_ev(skb); + sk->state = TCP_CLOSING; + ev = llc_conn_ev(skb); ev->type = LLC_CONN_EV_TYPE_PRIM; ev->data.prim.prim = LLC_DISC_PRIM; ev->data.prim.type = LLC_PRIM_TYPE_REQ; - ev->data.prim.data = prim; - rc = llc_conn_send_ev(sk, skb); + ev->data.prim.data = NULL; + rc = llc_conn_state_process(sk, skb); out: - release_sock(sk); sock_put(sk); return rc; } /** - * llc_rst_req_handler - Resets an established LLC connection + * llc_build_and_send_reset_pkt - Resets an established LLC connection * @prim: pointer to structure that contains service parameters. * * Called when upper layer wants to reset an established LLC connection - * with a remote machine. this function packages a proper event and sends + * with a remote machine. This function packages a proper event and sends * it to connection component state machine. Returns 0 for success, 1 * otherwise. */ -static int llc_rst_req_handler(struct llc_prim_if_block *prim) +int llc_build_and_send_reset_pkt(struct sock *sk, + struct llc_prim_if_block *prim) { - struct sk_buff *skb; int rc = 1; - struct sock *sk = prim->data->res.sk; + struct sk_buff *skb = alloc_skb(0, GFP_ATOMIC); - lock_sock(sk); - skb = alloc_skb(1, GFP_ATOMIC); if (skb) { struct llc_conn_state_ev *ev = llc_conn_ev(skb); @@ -437,87 +345,10 @@ static int llc_rst_req_handler(struct llc_prim_if_block *prim) ev->data.prim.prim = LLC_RESET_PRIM; ev->data.prim.type = LLC_PRIM_TYPE_REQ; ev->data.prim.data = prim; - rc = llc_conn_send_ev(sk, skb); + rc = llc_conn_state_process(sk, skb); } - release_sock(sk); return rc; } -/* We don't support flow control. The original code from procom has - * some bits, but for now I'm cleaning this - */ -static int llc_flowcontrol_req_handler(struct llc_prim_if_block *prim) -{ - return 1; -} - -/** - * llc_sap_resp - Sends response to peer - * @prim: pointer to structure that contains service parameters - * - * This function is a interface function to upper layer. each one who - * wants to response to an indicate can call this function via calling - * sap_resp with proper service parameters. Returns 0 for success, 1 - * otherwise. - */ -static int llc_sap_resp(struct llc_prim_if_block *prim) -{ - u16 rc = 1; - /* network layer RESPONSE primitive received; package primitive - * as an event and send it to the connection event handler - */ - if (prim->prim < LLC_NBR_PRIMITIVES) - /* valid primitive; call the function to handle it */ - rc = llc_resp_prim[prim->prim](prim); - return rc; -} - -/** - * llc_conn_rsp_handler - Response to connect indication - * @prim: pointer to structure that contains response info. - * - * Response to connect indication. - */ -static int llc_conn_rsp_handler(struct llc_prim_if_block *prim) -{ - struct sock *sk = prim->data->conn.sk; - - llc_sk(sk)->link = prim->data->conn.link; - return 0; -} - -/** - * llc_rst_rsp_handler - Response to RESET indication - * @prim: pointer to structure that contains response info - * - * Returns 0 for success, 1 otherwise - */ -static int llc_rst_rsp_handler(struct llc_prim_if_block *prim) -{ - int rc = 1; - /* - * Network layer supplies connection handle; map it to a connection; - * package as event and send it to connection event handler - */ - struct sock *sk = prim->data->res.sk; - struct sk_buff *skb = alloc_skb(1, GFP_ATOMIC); - - if (skb) { - struct llc_conn_state_ev *ev = llc_conn_ev(skb); - - ev->type = LLC_CONN_EV_TYPE_PRIM; - ev->data.prim.prim = LLC_RESET_PRIM; - ev->data.prim.type = LLC_PRIM_TYPE_RESP; - ev->data.prim.data = prim; - rc = llc_conn_send_ev(sk, skb); - } - return rc; -} - -static int llc_no_rsp_handler(struct llc_prim_if_block *prim) -{ - return 0; -} - EXPORT_SYMBOL(llc_sap_open); EXPORT_SYMBOL(llc_sap_close); diff --git a/net/llc/llc_mac.c b/net/llc/llc_mac.c index d71eae9c79a0..381ea3f58a78 100644 --- a/net/llc/llc_mac.c +++ b/net/llc/llc_mac.c @@ -27,14 +27,17 @@ #include <net/llc_s_ev.h> #include <linux/trdevice.h> -#if 1 +#if 0 #define dprintk(args...) printk(KERN_DEBUG args) #else #define dprintk(args...) #endif -/* function prototypes */ +u8 llc_mac_null_var[IFHWADDRLEN]; + static void fix_up_incoming_skb(struct sk_buff *skb); +static void llc_station_rcv(struct sk_buff *skb); +static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb); /** * mac_send_pdu - Sends PDU to specific device. @@ -52,7 +55,7 @@ int mac_send_pdu(struct sk_buff *skb) int pri = GFP_ATOMIC, rc = -1; if (!skb->dev) { - dprintk(KERN_ERR "%s: skb->dev == NULL!", __FUNCTION__); + dprintk("%s: skb->dev == NULL!", __FUNCTION__); goto out; } if (skb->sk) @@ -67,29 +70,30 @@ out: } /** - * mac_indicate - 802.2 entry point from net lower layers + * llc_rcv - 802.2 entry point from net lower layers * @skb: received pdu * @dev: device that receive pdu * @pt: packet type * * When the system receives a 802.2 frame this function is called. It * checks SAP and connection of received pdu and passes frame to - * llc_pdu_router for sending to proper state machine. If frame is - * related to a busy connection (a connection is sending data now), - * function queues this frame in connection's backlog. + * llc_{station,sap,conn}_rcv for sending to proper state machine. If + * the frame is related to a busy connection (a connection is sending + * data now), it queues this frame in the connection's backlog. */ -int mac_indicate(struct sk_buff *skb, struct net_device *dev, +int llc_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt) { struct llc_sap *sap; struct llc_pdu_sn *pdu; u8 dest; - /* When the interface is in promisc. mode, drop all the crap that it + /* + * When the interface is in promisc. mode, drop all the crap that it * receives, do not try to analyse it. */ if (skb->pkt_type == PACKET_OTHERHOST) { - dprintk(KERN_INFO "%s: PACKET_OTHERHOST\n", __FUNCTION__); + dprintk("%s: PACKET_OTHERHOST\n", __FUNCTION__); goto drop; } skb = skb_share_check(skb, GFP_ATOMIC); @@ -98,17 +102,19 @@ int mac_indicate(struct sk_buff *skb, struct net_device *dev, fix_up_incoming_skb(skb); pdu = llc_pdu_sn_hdr(skb); if (!pdu->dsap) { /* NULL DSAP, refer to station */ - if (llc_pdu_router(NULL, NULL, skb, 0)) - goto drop; + dprintk("%s: calling llc_station_rcv!\n", __FUNCTION__); + llc_station_rcv(skb); goto out; } sap = llc_sap_find(pdu->dsap); - if (!sap) /* unknown SAP */ + if (!sap) {/* unknown SAP */ + dprintk("%s: llc_sap_find(%02X) failed!\n", __FUNCTION__, pdu->dsap); goto drop; + } llc_decode_pdu_type(skb, &dest); if (dest == LLC_DEST_SAP) { /* type 1 services */ - if (llc_pdu_router(sap, NULL, skb, LLC_TYPE_1)) - goto drop; + dprintk("%s: calling llc_sap_rcv!\n", __FUNCTION__); + llc_sap_rcv(sap, skb); } else if (dest == LLC_DEST_CONN) { struct llc_addr saddr, daddr; struct sock *sk; @@ -119,34 +125,42 @@ int mac_indicate(struct sk_buff *skb, struct net_device *dev, llc_pdu_decode_da(skb, daddr.mac); llc_pdu_decode_dsap(skb, &daddr.lsap); - sk = llc_find_sock(sap, &saddr, &daddr); - if (!sk) { /* didn't find an active connection; allocate a - * connection to use; associate it with this SAP - */ - sk = llc_sock_alloc(); - if (!sk) + sk = llc_lookup_established(sap, &saddr, &daddr); + if (!sk) { + /* + * Didn't find an active connection; verify if there + * is a listening socket for this llc addr + */ + struct llc_opt *llc; + struct sock *parent; + + parent = llc_lookup_listener(sap, &daddr); + + if (!parent) { + dprintk("llc_lookup_listener failed!\n"); + goto drop; + } + + sk = llc_sk_alloc(parent->family, GFP_ATOMIC); + if (!sk) { + sock_put(parent); goto drop; - memcpy(&llc_sk(sk)->daddr, &saddr, sizeof(saddr)); + } + llc = llc_sk(sk); + memcpy(&llc->laddr, &daddr, sizeof(llc->laddr)); + memcpy(&llc->daddr, &saddr, sizeof(llc->daddr)); llc_sap_assign_sock(sap, sk); sock_hold(sk); - } + sock_put(parent); + skb->sk = parent; + } else + skb->sk = sk; bh_lock_sock(sk); if (!sk->lock.users) { - /* FIXME: Check this on SMP as it is now calling - * llc_pdu_router _with_ the lock held. - * Old comment: - * With the current code one can't call - * llc_pdu_router with the socket lock held, cause - * it'll route the pdu to the upper layers and it can - * reenter llc and in llc_req_prim will try to grab - * the same lock, maybe we should use spin_trylock_bh - * in the llc_req_prim (llc_data_req_handler, etc) and - * add the request to the backlog, well see... - */ - rc = llc_pdu_router(llc_sk(sk)->sap, sk, skb, - LLC_TYPE_2); + /* rc = */ llc_conn_rcv(sk, skb); + rc = 0; } else { - dprintk(KERN_INFO "%s: add to backlog\n", __FUNCTION__); + dprintk("%s: adding to backlog...\n", __FUNCTION__); llc_set_backlog_type(skb, LLC_PACKET); sk_add_backlog(sk, skb); rc = 0; @@ -191,53 +205,56 @@ static void fix_up_incoming_skb(struct sk_buff *skb) } } -/** - * llc_pdu_router - routes received pdus to the upper layers - * @sap: current sap component structure. - * @sk: current connection structure. - * @frame: received frame. - * @type: type of received frame, that is LLC_TYPE_1 or LLC_TYPE_2 +/* + * llc_station_rcv - send received pdu to the station state machine + * @skb: received frame. * - * Queues received PDUs from LLC_MAC PDU receive queue until queue is - * empty; examines LLC header to determine the destination of PDU, if DSAP - * is NULL then data unit destined for station else frame destined for SAP - * or connection; finds a matching open SAP, if one, forwards the packet - * to it; if no matching SAP, drops the packet. Returns 0 or the return of - * llc_conn_send_ev (that may well result in the connection being - * destroyed) + * Sends data unit to station state machine. */ -int llc_pdu_router(struct llc_sap *sap, struct sock* sk, - struct sk_buff *skb, u8 type) +static void llc_station_rcv(struct sk_buff *skb) { - struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); - int rc = 0; + struct llc_station *station = llc_station_get(); + struct llc_station_state_ev *ev = llc_station_ev(skb); - if (!pdu->dsap) { - struct llc_station *station = llc_station_get(); - struct llc_station_state_ev *ev = llc_station_ev(skb); + ev->type = LLC_STATION_EV_TYPE_PDU; + ev->data.pdu.reason = 0; + llc_station_state_process(station, skb); +} - ev->type = LLC_STATION_EV_TYPE_PDU; - ev->data.pdu.reason = 0; - llc_station_send_ev(station, skb); - } else if (type == LLC_TYPE_1) { - struct llc_sap_state_ev *ev = llc_sap_ev(skb); - ev->type = LLC_SAP_EV_TYPE_PDU; - ev->data.pdu.reason = 0; - llc_sap_send_ev(sap, skb); - } else if (type == LLC_TYPE_2) { - struct llc_conn_state_ev *ev = llc_conn_ev(skb); - struct llc_opt *llc = llc_sk(sk); +/** + * llc_conn_rcv - sends received pdus to the connection state machine + * @sk: current connection structure. + * @skb: received frame. + * + * Sends received pdus to the connection state machine. + */ +int llc_conn_rcv(struct sock* sk, struct sk_buff *skb) +{ + struct llc_conn_state_ev *ev = llc_conn_ev(skb); + struct llc_opt *llc = llc_sk(sk); - if (!llc->dev) - llc->dev = skb->dev; + if (!llc->dev) + llc->dev = skb->dev; + ev->type = LLC_CONN_EV_TYPE_PDU; + ev->data.pdu.reason = 0; + return llc_conn_state_process(sk, skb); +} - ev->type = LLC_CONN_EV_TYPE_PDU; - ev->data.pdu.reason = 0; - rc = llc_conn_send_ev(sk, skb); - } else - rc = -EINVAL; - return rc; +/** + * llc_sap_rcv - sends received pdus to the sap state machine + * @sap: current sap component structure. + * @skb: received frame. + * + * Sends received pdus to the sap state machine. + */ +static void llc_sap_rcv(struct llc_sap *sap, struct sk_buff *skb) +{ + struct llc_sap_state_ev *ev = llc_sap_ev(skb); + + ev->type = LLC_SAP_EV_TYPE_PDU; + ev->data.pdu.reason = 0; + llc_sap_state_process(sap, skb); } /** diff --git a/net/llc/llc_main.c b/net/llc/llc_main.c index 0aee057d1909..cdb0b6e6020b 100644 --- a/net/llc/llc_main.c +++ b/net/llc/llc_main.c @@ -52,6 +52,11 @@ static int llc_rtn_all_conns(struct llc_sap *sap); static struct llc_station llc_main_station; /* only one of its kind */ +#undef LLC_REFCNT_DEBUG +#ifdef LLC_REFCNT_DEBUG +static atomic_t llc_sock_nr; +#endif + /** * llc_sap_alloc - allocates and initializes sap. * @@ -136,7 +141,7 @@ struct llc_sap *llc_sap_find(u8 sap_value) * * This function processes frames that has received and timers that has * expired during sending an I pdu (refer to data_req_handler). frames - * queue by mac_indicate function (llc_mac.c) and timers queue by timer + * queue by llc_rcv function (llc_mac.c) and timers queue by timer * callback functions(llc_c_ac.c). */ static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb) @@ -146,13 +151,13 @@ static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb) if (llc_backlog_type(skb) == LLC_PACKET) { if (llc->state > 1) /* not closed */ - rc = llc_pdu_router(llc->sap, sk, skb, LLC_TYPE_2); + rc = llc_conn_rcv(sk, skb); else kfree_skb(skb); } else if (llc_backlog_type(skb) == LLC_EVENT) { /* timer expiration event */ if (llc->state > 1) /* not closed */ - rc = llc_conn_send_ev(sk, skb); + rc = llc_conn_state_process(sk, skb); else llc_conn_free_ev(skb); kfree_skb(skb); @@ -165,10 +170,12 @@ static int llc_backlog_rcv(struct sock *sk, struct sk_buff *skb) } /** - * llc_sock_init - Initialize a socket with default llc values. + * llc_sk_init - Initializes a socket with default llc values. * @sk: socket to intiailize. + * + * Initializes a socket with default llc values. */ -int llc_sock_init(struct sock* sk) +int llc_sk_init(struct sock* sk) { struct llc_opt *llc = kmalloc(sizeof(*llc), GFP_ATOMIC); int rc = -ENOMEM; @@ -198,61 +205,83 @@ out: } /** - * __llc_sock_alloc - Allocates LLC sock + * llc_sk_alloc - Allocates LLC sock + * @family: upper layer protocol family + * @priority: for allocation (%GFP_KERNEL, %GFP_ATOMIC, etc) * * Allocates a LLC sock and initializes it. Returns the new LLC sock * or %NULL if there's no memory available for one */ -struct sock *__llc_sock_alloc(void) +struct sock *llc_sk_alloc(int family, int priority) { - struct sock *sk = sk_alloc(PF_LLC, GFP_ATOMIC, 1, NULL); + struct sock *sk = sk_alloc(family, priority, 1, NULL); + MOD_INC_USE_COUNT; if (!sk) - goto out; - if (llc_sock_init(sk)) + goto decmod; + if (llc_sk_init(sk)) goto outsk; sock_init_data(NULL, sk); +#ifdef LLC_REFCNT_DEBUG + atomic_inc(&llc_sock_nr); + printk(KERN_DEBUG "LLC socket %p created in %s, now we have %d alive\n", sk, + __FUNCTION__, atomic_read(&llc_sock_nr)); +#endif out: return sk; outsk: sk_free(sk); sk = NULL; +decmod: + MOD_DEC_USE_COUNT; goto out; } /** - * __llc_sock_free - Frees a LLC socket + * llc_sk_free - Frees a LLC socket * @sk - socket to free * * Frees a LLC socket */ -void __llc_sock_free(struct sock *sk, u8 free) +void llc_sk_free(struct sock *sk) { struct llc_opt *llc = llc_sk(sk); llc->state = LLC_CONN_OUT_OF_SVC; - /* stop all (possibly) running timers */ + /* Stop all (possibly) running timers */ llc_conn_ac_stop_all_timers(sk, NULL); - /* handle return of frames on lists */ -#if 0 +#ifdef DEBUG_LLC_CONN_ALLOC printk(KERN_INFO "%s: unackq=%d, txq=%d\n", __FUNCTION__, skb_queue_len(&llc->pdu_unack_q), skb_queue_len(&sk->write_queue)); #endif + skb_queue_purge(&sk->receive_queue); skb_queue_purge(&sk->write_queue); skb_queue_purge(&llc->pdu_unack_q); - if (free) - sock_put(sk); +#ifdef LLC_REFCNT_DEBUG + if (atomic_read(&sk->refcnt) != 1) { + printk(KERN_DEBUG "Destruction of LLC sock %p delayed in %s, cnt=%d\n", + sk, __FUNCTION__, atomic_read(&sk->refcnt)); + printk(KERN_DEBUG "%d LLC sockets are still alive\n", + atomic_read(&llc_sock_nr)); + } else { + atomic_dec(&llc_sock_nr); + printk(KERN_DEBUG "LLC socket %p released in %s, %d are still alive\n", sk, + __FUNCTION__, atomic_read(&llc_sock_nr)); + } +#endif + sock_put(sk); + MOD_DEC_USE_COUNT; } /** - * llc_sock_reset - resets a connection + * llc_sk_reset - resets a connection * @sk: LLC socket to reset * * Resets a connection to the out of service state. Stops its timers * and frees any frames in the queues of the connection. */ -void llc_sock_reset(struct sock *sk) +void llc_sk_reset(struct sock *sk) { struct llc_opt *llc = llc_sk(sk); @@ -286,8 +315,6 @@ void llc_sock_reset(struct sock *sk) static int llc_rtn_all_conns(struct llc_sap *sap) { int rc = 0; - union llc_u_prim_data prim_data; - struct llc_prim_if_block prim; struct list_head *entry, *tmp; spin_lock_bh(&sap->sk_list.lock); @@ -296,12 +323,8 @@ static int llc_rtn_all_conns(struct llc_sap *sap) list_for_each_safe(entry, tmp, &sap->sk_list.list) { struct llc_opt *llc = list_entry(entry, struct llc_opt, node); - prim.sap = sap; - prim_data.disc.sk = llc->sk; - prim.prim = LLC_DISC_PRIM; - prim.data = &prim_data; llc->state = LLC_CONN_STATE_TEMP; - if (sap->req(&prim)) + if (llc_send_disc(llc->sk)) rc = 1; } out: @@ -320,14 +343,14 @@ struct llc_station *llc_station_get(void) } /** - * llc_station_send_ev: queue event and try to process queue. + * llc_station_state_process: queue event and try to process queue. * @station: Address of the station * @skb: Address of the event * * Queues an event (on the station event queue) for handling by the * station state machine and attempts to process any queued-up events. */ -void llc_station_send_ev(struct llc_station *station, struct sk_buff *skb) +void llc_station_state_process(struct llc_station *station, struct sk_buff *skb) { spin_lock_bh(&station->ev_q.lock); skb_queue_tail(&station->ev_q.list, skb); @@ -557,13 +580,13 @@ unlock: static struct packet_type llc_packet_type = { .type = __constant_htons(ETH_P_802_2), - .func = mac_indicate, + .func = llc_rcv, .data = (void *)1, }; static struct packet_type llc_tr_packet_type = { .type = __constant_htons(ETH_P_TR_802_2), - .func = mac_indicate, + .func = llc_rcv, .data = (void *)1, }; @@ -585,7 +608,7 @@ static int __init llc_init(void) skb_queue_head_init(&llc_main_station.mac_pdu_q); skb_queue_head_init(&llc_main_station.ev_q.list); spin_lock_init(&llc_main_station.ev_q.lock); - skb = alloc_skb(1, GFP_ATOMIC); + skb = alloc_skb(0, GFP_ATOMIC); if (!skb) goto err; llc_build_offset_table(); diff --git a/net/llc/llc_pdu.c b/net/llc/llc_pdu.c index f62dec772a0a..069ec96c9312 100644 --- a/net/llc/llc_pdu.c +++ b/net/llc/llc_pdu.c @@ -18,7 +18,7 @@ #include <net/llc_mac.h> #include <net/llc_main.h> -static int llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type); +static void llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type); static __inline__ int llc_get_hdr_len(u8 pdu_type); static u8 llc_pdu_get_pf_bit(struct llc_pdu_sn *pdu); @@ -60,9 +60,7 @@ void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value) u8 pdu_type; struct llc_pdu_sn *pdu; - if (llc_pdu_decode_pdu_type(skb, &pdu_type)) - goto out; - + llc_pdu_decode_pdu_type(skb, &pdu_type); pdu = llc_pdu_sn_hdr(skb); switch (pdu_type) { @@ -74,7 +72,6 @@ void llc_pdu_set_pf_bit(struct sk_buff *skb, u8 bit_value) pdu->ctrl_1 |= (pdu->ctrl_1 & 0xEF) | (bit_value << 4); break; } -out:; } /** @@ -86,15 +83,12 @@ out:; * PDU). In I or S pdus, p/f bit is right bit of fourth byte in header. In * U pdus p/f bit is fifth bit of third byte. */ -int llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit) +void llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit) { u8 pdu_type; struct llc_pdu_sn *pdu; - int rc = llc_pdu_decode_pdu_type(skb, &pdu_type); - - if (rc) - goto out; + llc_pdu_decode_pdu_type(skb, &pdu_type); pdu = llc_pdu_sn_hdr(skb); switch (pdu_type) { @@ -106,22 +100,19 @@ int llc_pdu_decode_pf_bit(struct sk_buff *skb, u8 *pf_bit) *pf_bit = (pdu->ctrl_1 & LLC_U_PF_BIT_MASK) >> 4; break; } -out: - return 0; } /** - * llc_pdu_decode_cr_bit - extracs command response bit from LLC header + * llc_pdu_decode_cr_bit - extracts command response bit from LLC header * @skb: input skb that c/r bit must be extracted from it. * @cr_bit: command/response bit (0 or 1). * * This function extracts command/response bit from LLC header. this bit * is right bit of source SAP. */ -int llc_pdu_decode_cr_bit(struct sk_buff *skb, u8 *cr_bit) +void llc_pdu_decode_cr_bit(struct sk_buff *skb, u8 *cr_bit) { *cr_bit = llc_pdu_un_hdr(skb)->ssap & LLC_PDU_CMD_RSP_MASK; - return 0; } /** @@ -131,13 +122,12 @@ int llc_pdu_decode_cr_bit(struct sk_buff *skb, u8 *cr_bit) * * This function extracts source address(MAC) of input frame. */ -int llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa) +void llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa) { if (skb->protocol == ntohs(ETH_P_802_2)) memcpy(sa, ((struct ethhdr *)skb->mac.raw)->h_source, ETH_ALEN); else if (skb->protocol == ntohs(ETH_P_TR_802_2)) memcpy(sa, ((struct trh_hdr *)skb->mac.raw)->saddr, ETH_ALEN); - return 0; } /** @@ -147,13 +137,12 @@ int llc_pdu_decode_sa(struct sk_buff *skb, u8 *sa) * * This function extracts destination address(MAC) of input frame. */ -int llc_pdu_decode_da(struct sk_buff *skb, u8 *da) +void llc_pdu_decode_da(struct sk_buff *skb, u8 *da) { if (skb->protocol == ntohs(ETH_P_802_2)) memcpy(da, ((struct ethhdr *)skb->mac.raw)->h_dest, ETH_ALEN); else if (skb->protocol == ntohs(ETH_P_TR_802_2)) memcpy(da, ((struct trh_hdr *)skb->mac.raw)->daddr, ETH_ALEN); - return 0; } /** @@ -164,10 +153,9 @@ int llc_pdu_decode_da(struct sk_buff *skb, u8 *da) * This function extracts destination SAP of input frame. right bit of * DSAP designates individual/group SAP. */ -int llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap) +void llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap) { *dsap = llc_pdu_un_hdr(skb)->dsap & 0xFE; - return 0; } /** @@ -175,13 +163,12 @@ int llc_pdu_decode_dsap(struct sk_buff *skb, u8 *dsap) * @skb: input skb that source SAP must be extracted from it. * @ssap: source SAP (output argument). * - * This function extracts source SAP of input frame. right bit of SSAP is + * This function extracts source SAP of input frame. Right bit of SSAP is * command/response bit. */ -int llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap) +void llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap) { *ssap = llc_pdu_un_hdr(skb)->ssap & 0xFE; - return 0; } /** @@ -190,13 +177,12 @@ int llc_pdu_decode_ssap(struct sk_buff *skb, u8 *ssap) * * This function sets third byte of LLC header as a UI PDU. */ -int llc_pdu_init_as_ui_cmd(struct sk_buff *skb) +void llc_pdu_init_as_ui_cmd(struct sk_buff *skb) { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); pdu->ctrl_1 = LLC_PDU_TYPE_U; pdu->ctrl_1 |= LLC_1_PDU_CMD_UI; - return 0; } /** @@ -206,8 +192,8 @@ int llc_pdu_init_as_ui_cmd(struct sk_buff *skb) * This function sets third,fourth,fifth and sixth bytes of LLC header as * a XID PDU. */ -int llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported, - u8 rx_window) +void llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported, + u8 rx_window) { struct llc_xid_info *xid_info; struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); @@ -220,7 +206,6 @@ int llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported, xid_info->type = svcs_supported; xid_info->rw = rx_window << 1; /* size of recieve window */ skb_put(skb, 3); - return 0; } /** @@ -229,14 +214,13 @@ int llc_pdu_init_as_xid_cmd(struct sk_buff *skb, u8 svcs_supported, * * Sets a PDU as TEST */ -int llc_pdu_init_as_test_cmd(struct sk_buff *skb) +void llc_pdu_init_as_test_cmd(struct sk_buff *skb) { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); pdu->ctrl_1 = LLC_PDU_TYPE_U; pdu->ctrl_1 |= LLC_1_PDU_CMD_TEST; pdu->ctrl_1 |= LLC_U_PF_BIT_MASK; - return 0; } /** @@ -246,18 +230,17 @@ int llc_pdu_init_as_test_cmd(struct sk_buff *skb) * * Builds a pdu frame as a DISC command. */ -int llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit) +void llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit) { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); pdu->ctrl_1 = LLC_PDU_TYPE_U; pdu->ctrl_1 |= LLC_2_PDU_CMD_DISC; pdu->ctrl_1 |= ((p_bit & 1) << 4) & LLC_U_PF_BIT_MASK; - return 0; } /** - * pdu_init_as_i_cmd - builds I pdu + * llc_pdu_init_as_i_cmd - builds I pdu * @skb: Address of the skb to build * @p_bit: The P bit to set in the PDU * @ns: The sequence number of the data PDU @@ -265,7 +248,7 @@ int llc_pdu_init_as_disc_cmd(struct sk_buff *skb, u8 p_bit) * * Builds a pdu frame as an I command. */ -int llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr) +void llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); @@ -274,18 +257,17 @@ int llc_pdu_init_as_i_cmd(struct sk_buff *skb, u8 p_bit, u8 ns, u8 nr) pdu->ctrl_2 |= (p_bit & LLC_I_PF_BIT_MASK); /* p/f bit */ pdu->ctrl_1 |= (ns << 1) & 0xFE; /* set N(S) in bits 2..8 */ pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ - return 0; } /** - * pdu_init_as_rej_cmd - builds REJ PDU + * llc_pdu_init_as_rej_cmd - builds REJ PDU * @skb: Address of the skb to build * @p_bit: The P bit to set in the PDU * @nr: The seq. number of the expected I PDU from the remote * * Builds a pdu frame as a REJ command. */ -int llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) +void llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); @@ -295,18 +277,17 @@ int llc_pdu_init_as_rej_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) pdu->ctrl_2 |= p_bit & LLC_S_PF_BIT_MASK; pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */ pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ - return 0; } /** - * pdu_init_as_rnr_cmd - builds RNR pdu + * llc_pdu_init_as_rnr_cmd - builds RNR pdu * @skb: Address of the skb to build * @p_bit: The P bit to set in the PDU * @nr: The seq. number of the expected I PDU from the remote * * Builds a pdu frame as an RNR command. */ -int llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) +void llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); @@ -316,18 +297,17 @@ int llc_pdu_init_as_rnr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) pdu->ctrl_2 |= p_bit & LLC_S_PF_BIT_MASK; pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */ pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ - return 0; } /** - * pdu_init_as_rr_cmd - Builds RR pdu + * llc_pdu_init_as_rr_cmd - Builds RR pdu * @skb: Address of the skb to build * @p_bit: The P bit to set in the PDU * @nr: The seq. number of the expected I PDU from the remote * * Builds a pdu frame as an RR command. */ -int llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) +void llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); @@ -336,53 +316,50 @@ int llc_pdu_init_as_rr_cmd(struct sk_buff *skb, u8 p_bit, u8 nr) pdu->ctrl_2 = p_bit & LLC_S_PF_BIT_MASK; pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */ pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ - return 0; } /** - * pdu_init_as_sabme_cmd - builds SABME pdu + * llc_pdu_init_as_sabme_cmd - builds SABME pdu * @skb: Address of the skb to build * @p_bit: The P bit to set in the PDU * * Builds a pdu frame as an SABME command. */ -int llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit) +void llc_pdu_init_as_sabme_cmd(struct sk_buff *skb, u8 p_bit) { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); pdu->ctrl_1 = LLC_PDU_TYPE_U; pdu->ctrl_1 |= LLC_2_PDU_CMD_SABME; pdu->ctrl_1 |= ((p_bit & 1) << 4) & LLC_U_PF_BIT_MASK; - return 0; } /** - * pdu_init_as_dm_rsp - builds DM response pdu + * llc_pdu_init_as_dm_rsp - builds DM response pdu * @skb: Address of the skb to build * @f_bit: The F bit to set in the PDU * * Builds a pdu frame as a DM response. */ -int llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit) +void llc_pdu_init_as_dm_rsp(struct sk_buff *skb, u8 f_bit) { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); pdu->ctrl_1 = LLC_PDU_TYPE_U; pdu->ctrl_1 |= LLC_2_PDU_RSP_DM; pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK; - return 0; } /** - * pdu_init_as_xid_rsp - builds XID response PDU + * llc_pdu_init_as_xid_rsp - builds XID response PDU * @skb: Address of the skb to build * @svcs_supported: The class of the LLC (I or II) * @rx_window: The size of the receive window of the LLC * * Builds a pdu frame as an XID response. */ -int llc_pdu_init_as_xid_rsp(struct sk_buff *skb, u8 svcs_supported, - u8 rx_window) +void llc_pdu_init_as_xid_rsp(struct sk_buff *skb, u8 svcs_supported, + u8 rx_window) { struct llc_xid_info *xid_info; struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); @@ -396,17 +373,16 @@ int llc_pdu_init_as_xid_rsp(struct sk_buff *skb, u8 svcs_supported, xid_info->type = svcs_supported; xid_info->rw = rx_window << 1; skb_put(skb, 3); - return 0; } /** - * pdu_init_as_test_rsp - build TEST response PDU + * llc_pdu_init_as_test_rsp - build TEST response PDU * @skb: Address of the skb to build * @ev_skb: The received TEST command PDU frame * * Builds a pdu frame as a TEST response. */ -int llc_pdu_init_as_test_rsp(struct sk_buff *skb, struct sk_buff *ev_skb) +void llc_pdu_init_as_test_rsp(struct sk_buff *skb, struct sk_buff *ev_skb) { int dsize; struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); @@ -421,12 +397,11 @@ int llc_pdu_init_as_test_rsp(struct sk_buff *skb, struct sk_buff *ev_skb) memcpy(((u8 *)pdu) + 3, ((u8 *)ev_pdu) + 3, dsize); skb_put(skb, dsize); } - return 0; } /** - * pdu_init_as_frmr_rsp - builds FRMR response PDU - * @pdu_frame: Address of the frame to build + * llc_pdu_init_as_frmr_rsp - builds FRMR response PDU + * @skb: Address of the frame to build * @prev_pdu: The rejected PDU frame * @f_bit: The F bit to set in the PDU * @vs: tx state vari value for the data link conn at the rejecting LLC @@ -435,8 +410,8 @@ int llc_pdu_init_as_test_rsp(struct sk_buff *skb, struct sk_buff *ev_skb) * * Builds a pdu frame as a FRMR response. */ -int llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, struct llc_pdu_sn *prev_pdu, - u8 f_bit, u8 vs, u8 vr, u8 vzyxw) +void llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, struct llc_pdu_sn *prev_pdu, + u8 f_bit, u8 vs, u8 vr, u8 vzyxw) { struct llc_frmr_info *frmr_info; u8 prev_pf = 0; @@ -460,18 +435,17 @@ int llc_pdu_init_as_frmr_rsp(struct sk_buff *skb, struct llc_pdu_sn *prev_pdu, FRMR_INFO_SET_PDU_INVALID_Nr_IND(frmr_info, vzyxw); FRMR_INFO_SET_PDU_INVALID_Ns_IND(frmr_info, vzyxw); skb_put(skb, 5); - return 0; } /** - * pdu_init_as_rr_rsp - builds RR response pdu + * llc_pdu_init_as_rr_rsp - builds RR response pdu * @skb: Address of the skb to build * @f_bit: The F bit to set in the PDU * @nr: The seq. number of the expected data PDU from the remote * * Builds a pdu frame as an RR response. */ -int llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) +void llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); @@ -481,18 +455,17 @@ int llc_pdu_init_as_rr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK; pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */ pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ - return 0; } /** - * pdu_init_as_rej_rsp - builds REJ response pdu + * llc_pdu_init_as_rej_rsp - builds REJ response pdu * @skb: Address of the skb to build * @f_bit: The F bit to set in the PDU * @nr: The seq. number of the expected data PDU from the remote * * Builds a pdu frame as a REJ response. */ -int llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) +void llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); @@ -502,18 +475,17 @@ int llc_pdu_init_as_rej_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK; pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */ pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ - return 0; } /** - * pdu_init_as_rnr_rsp - builds RNR response pdu - * @pdu_frame: Address of the frame to build + * llc_pdu_init_as_rnr_rsp - builds RNR response pdu + * @skb: Address of the frame to build * @f_bit: The F bit to set in the PDU * @nr: The seq. number of the expected data PDU from the remote * * Builds a pdu frame as an RNR response. */ -int llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) +void llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) { struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); @@ -523,24 +495,22 @@ int llc_pdu_init_as_rnr_rsp(struct sk_buff *skb, u8 f_bit, u8 nr) pdu->ctrl_2 |= f_bit & LLC_S_PF_BIT_MASK; pdu->ctrl_1 &= 0x0F; /* setting bits 5..8 to zero(reserved) */ pdu->ctrl_2 |= (nr << 1) & 0xFE; /* set N(R) in bits 10..16 */ - return 0; } /** - * pdu_init_as_ua_rsp - builds UA response pdu + * llc_pdu_init_as_ua_rsp - builds UA response pdu * @skb: Address of the frame to build * @f_bit: The F bit to set in the PDU * * Builds a pdu frame as a UA response. */ -int llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit) +void llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit) { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); pdu->ctrl_1 = LLC_PDU_TYPE_U; pdu->ctrl_1 |= LLC_2_PDU_RSP_UA; pdu->ctrl_1 |= ((f_bit & 1) << 4) & LLC_U_PF_BIT_MASK; - return 0; } /** @@ -548,9 +518,9 @@ int llc_pdu_init_as_ua_rsp(struct sk_buff *skb, u8 f_bit) * @skb: input skb that type of it must be designated. * @type: type of PDU (output argument). * - * This function designates type of PDU (I,S or U). + * This function designates type of PDU (I, S or U). */ -static int llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type) +static void llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type) { struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb); @@ -561,7 +531,6 @@ static int llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type) *type = LLC_PDU_TYPE_S; } else *type = LLC_PDU_TYPE_I; - return 0; } /** @@ -571,7 +540,7 @@ static int llc_pdu_decode_pdu_type(struct sk_buff *skb, u8 *type) * * This function designates which component of LLC must handle this PDU. */ -int llc_decode_pdu_type(struct sk_buff *skb, u8 *dest) +void llc_decode_pdu_type(struct sk_buff *skb, u8 *dest) { u8 type = LLC_DEST_CONN; /* I-PDU or S-PDU type */ struct llc_pdu_sn *pdu = llc_pdu_sn_hdr(skb); @@ -596,7 +565,6 @@ int llc_decode_pdu_type(struct sk_buff *skb, u8 *dest) } out: *dest = type; - return 0; } /** diff --git a/net/llc/llc_s_ac.c b/net/llc/llc_s_ac.c index f2be18568aec..e3f8ff640a82 100644 --- a/net/llc/llc_s_ac.c +++ b/net/llc/llc_s_ac.c @@ -57,13 +57,10 @@ int llc_sap_action_send_ui(struct llc_sap *sap, struct sk_buff *skb) llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap, prim_data->daddr.lsap, LLC_PDU_CMD); - rc = llc_pdu_init_as_ui_cmd(skb); - if (rc) - goto out; + llc_pdu_init_as_ui_cmd(skb); rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac); if (!rc) llc_sap_send_pdu(sap, skb); -out: return rc; } @@ -85,13 +82,10 @@ int llc_sap_action_send_xid_c(struct llc_sap *sap, struct sk_buff *skb) llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap, prim_data->daddr.lsap, LLC_PDU_CMD); - rc = llc_pdu_init_as_xid_cmd(skb, LLC_XID_NULL_CLASS_2, 0); - if (rc) - goto out; + llc_pdu_init_as_xid_cmd(skb, LLC_XID_NULL_CLASS_2, 0); rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac); if (!rc) llc_sap_send_pdu(sap, skb); -out: return rc; } @@ -118,9 +112,7 @@ int llc_sap_action_send_xid_r(struct llc_sap *sap, struct sk_buff *skb) nskb->dev = skb->dev; llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, dsap, LLC_PDU_RSP); - rc = llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 0); - if (rc) - goto out; + llc_pdu_init_as_xid_rsp(nskb, LLC_XID_NULL_CLASS_2, 0); rc = lan_hdrs_init(nskb, mac_sa, mac_da); if (!rc) llc_sap_send_pdu(sap, nskb); @@ -146,13 +138,10 @@ int llc_sap_action_send_test_c(struct llc_sap *sap, struct sk_buff *skb) llc_pdu_header_init(skb, LLC_PDU_TYPE_U, prim_data->saddr.lsap, prim_data->daddr.lsap, LLC_PDU_CMD); - rc = llc_pdu_init_as_test_cmd(skb); - if (rc) - goto out; + llc_pdu_init_as_test_cmd(skb); rc = lan_hdrs_init(skb, prim_data->saddr.mac, prim_data->daddr.mac); if (!rc) llc_sap_send_pdu(sap, skb); -out: return rc; } @@ -171,9 +160,7 @@ int llc_sap_action_send_test_r(struct llc_sap *sap, struct sk_buff *skb) nskb->dev = skb->dev; llc_pdu_header_init(nskb, LLC_PDU_TYPE_U, sap->laddr.lsap, dsap, LLC_PDU_RSP); - rc = llc_pdu_init_as_test_rsp(nskb, skb); - if (rc) - goto out; + llc_pdu_init_as_test_rsp(nskb, skb); rc = lan_hdrs_init(nskb, mac_sa, mac_da); if (!rc) llc_sap_send_pdu(sap, nskb); diff --git a/net/llc/llc_sap.c b/net/llc/llc_sap.c index 9986782135b1..15ad186dcdd9 100644 --- a/net/llc/llc_sap.c +++ b/net/llc/llc_sap.c @@ -23,7 +23,6 @@ #include <net/llc_pdu.h> #include <linux/if_tr.h> -static void llc_sap_free_ev(struct llc_sap *sap, struct sk_buff *skb); static int llc_sap_next_state(struct llc_sap *sap, struct sk_buff *skb); static int llc_exec_sap_trans_actions(struct llc_sap *sap, struct llc_sap_state_trans *trans, @@ -52,8 +51,7 @@ void llc_sap_assign_sock(struct llc_sap *sap, struct sock *sk) * @sap: SAP * @sk: pointer to connection * - * This function removes a connection from connection_list of a SAP. - * List locking is performed by caller (rtn_all_conns). + * This function removes a connection from sk_list.list of a SAP. */ void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk) { @@ -64,23 +62,25 @@ void llc_sap_unassign_sock(struct llc_sap *sap, struct sock *sk) } /** - * llc_sap_send_ev - sends event to SAP state machine + * llc_sap_state_process - sends event to SAP state machine * @sap: pointer to SAP * @skb: pointer to occurred event * * After executing actions of the event, upper layer will be indicated * if needed(on receiving an UI frame). */ -void llc_sap_send_ev(struct llc_sap *sap, struct sk_buff *skb) +void llc_sap_state_process(struct llc_sap *sap, struct sk_buff *skb) { struct llc_sap_state_ev *ev = llc_sap_ev(skb); llc_sap_next_state(sap, skb); - if (ev->ind_cfm_flag == LLC_IND) { - skb_get(skb); + if (ev->ind_cfm_flag == LLC_IND) sap->ind(ev->prim); - } - llc_sap_free_ev(sap, skb); + else if (ev->type == LLC_SAP_EV_TYPE_PDU) + kfree_skb(skb); + else + printk(KERN_INFO ":%s !kfree_skb & it is %s in a list\n", + __FUNCTION__, skb->list ? "" : "NOT"); } /** @@ -143,19 +143,6 @@ void llc_sap_send_pdu(struct llc_sap *sap, struct sk_buff *skb) } /** - * llc_sap_free_ev - frees an sap event - * @sap: pointer to SAP - * @skb: released event - */ -static void llc_sap_free_ev(struct llc_sap *sap, struct sk_buff *skb) -{ - struct llc_sap_state_ev *ev = llc_sap_ev(skb); - - if (ev->type == LLC_SAP_EV_TYPE_PDU) - kfree_skb(skb); -} - -/** * llc_sap_next_state - finds transition, execs actions & change SAP state * @sap: pointer to SAP * @skb: happened event @@ -206,7 +193,7 @@ static struct llc_sap_state_trans *llc_find_sap_trans(struct llc_sap *sap, /* search thru events for this state until list exhausted or until * its obvious the event is not valid for the current state */ - for (next_trans = curr_state->transitions; next_trans [i]->ev; i++) + for (next_trans = curr_state->transitions; next_trans[i]->ev; i++) if (!next_trans[i]->ev(sap, skb)) { /* got event match; return it */ rc = next_trans[i]; diff --git a/net/llc/llc_sock.c b/net/llc/llc_sock.c index 4acbbd335228..74a6a6b26e57 100644 --- a/net/llc/llc_sock.c +++ b/net/llc/llc_sock.c @@ -11,6 +11,7 @@ * connections. * * Copyright (c) 2001 by Jay Schulist <jschlst@samba.org> + * 2002 by Arnaldo Carvalho de Melo <acme@conectiva.com.br> * * This program can be redistributed or modified under the terms of the * GNU General Public License as published by the Free Software Foundation. @@ -38,6 +39,7 @@ #include <net/llc_sap.h> #include <net/llc_pdu.h> #include <net/llc_conn.h> +#include <net/llc_mac.h> #include <linux/llc.h> #include <linux/if_arp.h> #include <linux/rtnetlink.h> @@ -46,7 +48,6 @@ /* remember: uninitialized global data is zeroed because its in .bss */ static u16 llc_ui_sap_last_autoport = LLC_SAP_DYN_START; static u16 llc_ui_sap_link_no_max[256]; -static u8 llc_ui_addrany[IFHWADDRLEN]; static struct sockaddr_llc llc_ui_addrnull; static struct proto_ops llc_ui_ops; static struct sock *llc_ui_sockets; @@ -54,8 +55,16 @@ static rwlock_t llc_ui_sockets_lock = RW_LOCK_UNLOCKED; static int llc_ui_indicate(struct llc_prim_if_block *prim); static int llc_ui_confirm(struct llc_prim_if_block *prim); -static int llc_ui_wait_for_conn(struct sock *sk, int seconds); -static int llc_ui_wait_for_disc(struct sock *sk, int seconds); +static int llc_ui_wait_for_conn(struct sock *sk, int timeout); +static int llc_ui_wait_for_disc(struct sock *sk, int timeout); +static int llc_ui_wait_for_data(struct sock *sk, int timeout); +static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout); + +#if 0 +#define dprintk(args...) printk(KERN_DEBUG args) +#else +#define dprintk(args...) +#endif /** * llc_ui_next_link_no - return the next unused link number for a sap @@ -63,64 +72,21 @@ static int llc_ui_wait_for_disc(struct sock *sk, int seconds); * * Return the next unused link number for a given sap. */ -static inline u16 llc_ui_next_link_no(int sap) +static __inline__ u16 llc_ui_next_link_no(int sap) { return llc_ui_sap_link_no_max[sap]++; } /** - * llc_ui_mac_match - determines if two mac addresses are the same - * @mac1: First mac address to compare. - * @mac2: Second mac address to compare. - * - * Determines if two given mac address are the same. Returns 0 if there - * is not a complete match up to len, 1 if a complete match up to len is - * found. - */ -static inline u8 llc_ui_mac_match(u8 *mac1, u8 *mac2) -{ - return !memcmp(mac1, mac2, IFHWADDRLEN); -} - -/** - * llc_ui_mac_null - determines if a address is a null mac address - * @mac: Mac address to test if null. - * - * Determines if a given address is a null mac address. Returns 0 if the - * address is not a null mac, 1 if the address is a null mac. - */ -static inline u8 llc_ui_mac_null(u8 *mac) -{ - return !memcmp(mac, llc_ui_addrany, IFHWADDRLEN); -} - -/** * llc_ui_addr_null - determines if a address structure is null * @addr: Address to test if null. */ -static inline u8 llc_ui_addr_null(struct sockaddr_llc *addr) +static __inline__ u8 llc_ui_addr_null(struct sockaddr_llc *addr) { return !memcmp(addr, &llc_ui_addrnull, sizeof(*addr)); } /** - * llc_ui_protocol_type - return eth protocol for ARP header type - * @arphrd: ARP header type. - * - * Given an ARP header type return the corresponding ethernet protocol. - * Returns 0 if ARP header type not supported or the corresponding - * ethernet protocol type. - */ -static inline u16 llc_ui_protocol_type(u16 arphrd) -{ - u16 rc = htons(ETH_P_802_2); - - if (arphrd == ARPHRD_IEEE802_TR) - rc = htons(ETH_P_TR_802_2); - return rc; -} - -/** * llc_ui_header_len - return length of llc header based on operation * @sk: Socket which contains a valid llc socket type. * @addr: Complete sockaddr_llc structure received from the user. @@ -129,7 +95,8 @@ static inline u16 llc_ui_protocol_type(u16 arphrd) * operation the user would like to perform and the type of socket. * Returns the correct llc header length. */ -static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr) +static __inline__ u8 llc_ui_header_len(struct sock *sk, + struct sockaddr_llc *addr) { u8 rc = LLC_PDU_LEN_U; @@ -141,138 +108,33 @@ static inline u8 llc_ui_header_len(struct sock *sk, struct sockaddr_llc *addr) } /** - * llc_ui_send_conn - send connect command for new llc2 connection - * @sap : Sap the socket is bound to. - * @addr: Source and destination fields provided by the user. - * @dev : Device which this connection should use. - * @link: Link number to assign to this connection. - * - * Send a connect command to the llc layer for a new llc2 connection. - * Returns 0 upon success, non-zero if action didn't succeed. - */ -static int llc_ui_send_conn(struct sock *sk, struct llc_sap *sap, - struct sockaddr_llc *addr, - struct net_device *dev, int link) -{ - struct llc_ui_opt *llc_ui = llc_ui_sk(sk); - union llc_u_prim_data prim_data; - struct llc_prim_if_block prim; - - prim.data = &prim_data; - prim.sap = sap; - prim.prim = LLC_CONN_PRIM; - prim_data.conn.dev = dev; - prim_data.conn.link = link; - prim_data.conn.sk = NULL; - prim_data.conn.handler = sk; - prim_data.conn.pri = 0; - prim_data.conn.saddr.lsap = llc_ui->addr.sllc_ssap; - prim_data.conn.daddr.lsap = addr->sllc_dsap; - memcpy(prim_data.conn.saddr.mac, dev->dev_addr, IFHWADDRLEN); - memcpy(prim_data.conn.daddr.mac, addr->sllc_dmac, IFHWADDRLEN); - return sap->req(&prim); -} - -/** - * llc_ui_send_disc - send disc command to llc layer - * @sk: Socket with valid llc information. - * - * Send a disconnect command to the llc layer for an established - * llc2 connection. - * Returns 0 upon success, non-zero if action did not succeed. - */ -static int llc_ui_send_disc(struct sock *sk) -{ - struct llc_ui_opt *llc_ui = llc_ui_sk(sk); - union llc_u_prim_data prim_data; - struct llc_prim_if_block prim; - int rc = 0; - - if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED) - goto out; - sk->state = TCP_CLOSING; - prim.data = &prim_data; - prim.sap = llc_ui->sap; - prim.prim = LLC_DISC_PRIM; - prim_data.disc.sk = llc_ui->core_sk; - prim_data.disc.link = llc_ui->link; - rc = llc_ui->sap->req(&prim); -out: - return rc; -} - -/** * llc_ui_send_data - send data via reliable llc2 connection - * @sap: Sap the socket is bound to. * @sk: Connection the socket is using. * @skb: Data the user wishes to send. * @addr: Source and destination fields provided by the user. + * @noblock: can we block waiting for data? * * Send data via reliable llc2 connection. - * Returns 0 upon success, non-zero if action did not succeed. + * Returns 0 upon success, non-zero if action did not succeed. */ -static int llc_ui_send_data(struct llc_sap *sap, struct sock* sk, - struct sk_buff *skb, struct sockaddr_llc *addr) +static int llc_ui_send_data(struct sock* sk, struct sk_buff *skb, + struct sockaddr_llc *addr, int noblock) { - union llc_u_prim_data prim_data; - struct llc_prim_if_block prim; - struct llc_ui_opt* llc_ui = llc_ui_sk(sk); - struct llc_opt* llc_core = llc_sk(llc_ui->core_sk); - int rc; + struct llc_opt* llc = llc_sk(sk); + int rc = 0; - prim.data = &prim_data; - prim.sap = sap; - prim.prim = LLC_DATA_PRIM; - prim_data.data.skb = skb; - prim_data.data.pri = 0; - prim_data.data.sk = llc_ui->core_sk; - skb->protocol = llc_ui_protocol_type(addr->sllc_arphrd); - sock_hold(sk); -try: - rc = sap->req(&prim); - if (rc != -EBUSY) - goto out; - rc = wait_event_interruptible(sk->socket->wait, !llc_ui->core_sk || - !llc_core->failed_data_req); + skb->protocol = llc_proto_type(addr->sllc_arphrd); + if (llc_data_accept_state(llc->state) || llc->p_flag) { + int timeout = sock_sndtimeo(sk, noblock); + + rc = llc_ui_wait_for_busy_core(sk, timeout); + } if (!rc) - goto try; - if (!llc_ui->core_sk) - rc = -ENOTCONN; -out: - sock_put(sk); + rc = llc_build_and_send_pkt(sk, skb); return rc; } /** - * llc_ui_send_llc1 - send llc1 prim data block to llc layer. - * @sap : Sap the socket is bound to. - * @skb : Data the user wishes to send. - * @addr : Source and destination fields provided by the user. - * @primitive: Action the llc layer should perform. - * - * Send an llc1 primitive data block to the llc layer for processing. - * This function is used for test, xid and unit_data messages. - * Returns 0 upon success, non-zero if action did not succeed. - */ -static int llc_ui_send_llc1(struct llc_sap *sap, struct sk_buff *skb, - struct sockaddr_llc *addr, int primitive) -{ - union llc_u_prim_data prim_data; - struct llc_prim_if_block prim; - - prim.data = &prim_data; - prim.sap = sap; - prim.prim = primitive; - prim_data.test.skb = skb; - prim_data.test.saddr.lsap = sap->laddr.lsap; - prim_data.test.daddr.lsap = addr->sllc_dsap; - skb->protocol = llc_ui_protocol_type(addr->sllc_arphrd); - memcpy(prim_data.test.saddr.mac, skb->dev->dev_addr, IFHWADDRLEN); - memcpy(prim_data.test.daddr.mac, addr->sllc_dmac, IFHWADDRLEN); - return sap->req(&prim); -} - -/** * llc_ui_find_sap - returns sap struct that matches sap number specified * @sap: Sap number to search for. * @@ -280,19 +142,19 @@ static int llc_ui_send_llc1(struct llc_sap *sap, struct sk_buff *skb, * structure which matches the sap number the user specified. * Returns llc_sap upon match, %NULL otherwise. */ -static inline struct llc_sap *llc_ui_find_sap(u8 sap) +static __inline__ struct llc_sap *llc_ui_find_sap(u8 sap) { struct sock *sk; struct llc_sap *s = NULL; read_lock_bh(&llc_ui_sockets_lock); for (sk = llc_ui_sockets; sk; sk = sk->next) { - struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + struct llc_opt *llc = llc_sk(sk); - if (!llc_ui->sap) + if (!llc->sap) continue; - if (llc_ui->sap->laddr.lsap == sap) { - s = llc_ui->sap; + if (llc->sap->laddr.lsap == sap) { + s = llc->sap; break; } } @@ -306,13 +168,13 @@ static struct sock *__llc_ui_find_sk_by_exact(struct llc_addr *laddr, struct sock *sk; for (sk = llc_ui_sockets; sk; sk = sk->next) { - struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + struct llc_opt *llc = llc_sk(sk); - if (llc_ui->addr.sllc_ssap == laddr->lsap && - llc_ui->addr.sllc_dsap == daddr->lsap && - llc_ui_mac_null(llc_ui->addr.sllc_mmac) && - llc_ui_mac_match(llc_ui->addr.sllc_smac, laddr->mac) && - llc_ui_mac_match(llc_ui->addr.sllc_dmac, daddr->mac)) + if (llc->addr.sllc_ssap == laddr->lsap && + llc->addr.sllc_dsap == daddr->lsap && + llc_mac_null(llc->addr.sllc_mmac) && + llc_mac_match(llc->addr.sllc_smac, laddr->mac) && + llc_mac_match(llc->addr.sllc_dmac, daddr->mac)) break; } return sk; @@ -335,31 +197,31 @@ static struct sock *__llc_ui_find_sk_by_addr(struct llc_addr *laddr, struct sock *sk, *tmp_sk; for (sk = llc_ui_sockets; sk; sk = sk->next) { - struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + struct llc_opt *llc = llc_sk(sk); - if (llc_ui->addr.sllc_ssap != laddr->lsap) + if (llc->addr.sllc_ssap != laddr->lsap) continue; - if (llc_ui_mac_null(llc_ui->addr.sllc_smac)) { - if (!llc_ui_mac_null(llc_ui->addr.sllc_mmac) && - !llc_ui_mac_match(llc_ui->addr.sllc_mmac, - laddr->mac)) + if (llc_mac_null(llc->addr.sllc_smac)) { + if (!llc_mac_null(llc->addr.sllc_mmac) && + !llc_mac_match(llc->addr.sllc_mmac, + laddr->mac)) continue; break; } - if (dev && !llc_ui_mac_null(llc_ui->addr.sllc_mmac) && - llc_ui_mac_match(llc_ui->addr.sllc_mmac, laddr->mac) && - llc_ui_mac_match(llc_ui->addr.sllc_smac, dev->dev_addr)) + if (dev && !llc_mac_null(llc->addr.sllc_mmac) && + llc_mac_match(llc->addr.sllc_mmac, laddr->mac) && + llc_mac_match(llc->addr.sllc_smac, dev->dev_addr)) break; if (dev->flags & IFF_LOOPBACK) break; - if (!llc_ui_mac_match(llc_ui->addr.sllc_smac, laddr->mac)) + if (!llc_mac_match(llc->addr.sllc_smac, laddr->mac)) continue; tmp_sk = __llc_ui_find_sk_by_exact(laddr, daddr); if (tmp_sk) { sk = tmp_sk; break; } - if (llc_ui_mac_null(llc_ui->addr.sllc_dmac)) + if (llc_mac_null(llc->addr.sllc_dmac)) break; } return sk; @@ -399,7 +261,7 @@ static struct sock *llc_ui_bh_find_sk_by_addr(struct llc_addr *addr, * * Insert a socket into the local llc socket list. */ -static inline void llc_ui_insert_socket(struct sock *sk) +static __inline__ void llc_ui_insert_socket(struct sock *sk) { write_lock_bh(&llc_ui_sockets_lock); sk->next = llc_ui_sockets; @@ -417,7 +279,7 @@ static inline void llc_ui_insert_socket(struct sock *sk) * * Remove a socket from the local llc socket list. */ -static inline void llc_ui_remove_socket(struct sock *sk) +static __inline__ void llc_ui_remove_socket(struct sock *sk) { write_lock_bh(&llc_ui_sockets_lock); if (sk->pprev) { @@ -425,7 +287,8 @@ static inline void llc_ui_remove_socket(struct sock *sk) sk->next->pprev = sk->pprev; *sk->pprev = sk->next; sk->pprev = NULL; - /* this only makes sense if the socket was inserted on the + /* + * This only makes sense if the socket was inserted on the * list, if sk->pprev is NULL it wasn't */ sock_put(sk); @@ -433,38 +296,13 @@ static inline void llc_ui_remove_socket(struct sock *sk) write_unlock_bh(&llc_ui_sockets_lock); } -/** - * llc_ui_destroy_sk - destroy socket - * @data: Socket which is to be destroyed. - * - * Really destroy the socket. - */ -static void llc_ui_destroy_sk(struct sock *sk) -{ - skb_queue_purge(&sk->receive_queue); - skb_queue_purge(&sk->write_queue); - sock_put(sk); - MOD_DEC_USE_COUNT; -} - -/** - * llc_ui_destroy_timer - try to destroy socket again - * @data: Socket which is to be destroyed. - * - * Attempt to destroy a socket which was previously destroyed but - * was still in use at the time. - */ -static void llc_ui_destroy_timer(unsigned long data) +static void llc_ui_sk_init(struct socket *sock, struct sock *sk) { - struct sock *sk = (struct sock *)data; - - if (!atomic_read(&sk->wmem_alloc) && - !atomic_read(&sk->rmem_alloc) && sk->dead) - llc_ui_destroy_sk(sk); - else { - sk->timer.expires = jiffies + SOCK_DESTROY_TIME; - add_timer(&sk->timer); - } + sk->type = sock->type; + sk->sleep = &sock->wait; + sk->socket = sock; + sock->sk = sk; + sock->ops = &llc_ui_ops; } /** @@ -479,31 +317,17 @@ static void llc_ui_destroy_timer(unsigned long data) static int llc_ui_create(struct socket *sock, int protocol) { struct sock *sk; - struct llc_ui_opt *llc_ui; int rc = -ESOCKTNOSUPPORT; - MOD_INC_USE_COUNT; - if (sock->type != SOCK_DGRAM && sock->type != SOCK_STREAM) - goto decmod; - rc = -ENOMEM; - sk = sk_alloc(PF_LLC, GFP_KERNEL, 1, NULL); - if (!sk) - goto decmod; - llc_ui = kmalloc(sizeof(*llc_ui), GFP_KERNEL); - if (!llc_ui) - goto outsk; - memset(llc_ui, 0, sizeof(*llc_ui)); - rc = 0; - sock_init_data(sock, sk); - llc_ui_sk(sk) = llc_ui; - sock->ops = &llc_ui_ops; -out: + if (sock->type == SOCK_DGRAM || sock->type == SOCK_STREAM) { + rc = -ENOMEM; + sk = llc_sk_alloc(PF_LLC, GFP_KERNEL); + if (sk) { + rc = 0; + llc_ui_sk_init(sock, sk); + } + } return rc; -outsk: - sk_free(sk); -decmod: - MOD_DEC_USE_COUNT; - goto out; } /** @@ -515,28 +339,26 @@ decmod: static int llc_ui_release(struct socket *sock) { struct sock *sk = sock->sk; - struct llc_ui_opt *llc_ui; + struct llc_opt *llc; if (!sk) goto out; - llc_ui = llc_ui_sk(sk); - if (llc_ui->core_sk && !llc_ui_send_disc(sk)) - llc_ui_wait_for_disc(sk, 255); - llc_ui_remove_socket(sk); - if (llc_ui->sap && !llc_ui_find_sap(llc_ui->sap->laddr.lsap)) - llc_sap_close(llc_ui->sap); - sock_orphan(sk); - sock->sk = NULL; - if (!atomic_read(&sk->wmem_alloc) && - !atomic_read(&sk->rmem_alloc) && sk->dead) - llc_ui_destroy_sk(sk); - else { - init_timer(&sk->timer); - sk->timer.expires = jiffies + SOCK_DESTROY_TIME; - sk->timer.function = llc_ui_destroy_timer; - sk->timer.data = (unsigned long)sk; - add_timer(&sk->timer); + sock_hold(sk); + lock_sock(sk); + llc = llc_sk(sk); + dprintk("%s: closing local(%02X) remote(%02X)\n", __FUNCTION__, + llc->laddr.lsap, llc->daddr.lsap); + if (!llc_send_disc(sk)) + llc_ui_wait_for_disc(sk, sk->rcvtimeo); + release_sock(sk); + if (!sk->zapped) { + llc_sap_unassign_sock(llc->sap, sk); + llc_ui_remove_socket(sk); } + if (llc->sap && list_empty(&llc->sap->sk_list.list)) + llc_sap_close(llc->sap); + sock_put(sk); + llc_sk_free(sk); out: return 0; } @@ -590,7 +412,7 @@ out: static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) { struct sock *sk = sock->sk; - struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + struct llc_opt *llc = llc_sk(sk); struct llc_sap *sap; struct net_device *dev = NULL; int rc = -EINVAL; @@ -598,14 +420,14 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) if (!sk->zapped) goto out; /* bind to a specific mac, optional. */ - if (!llc_ui_mac_null(addr->sllc_smac)) { + if (!llc_mac_null(addr->sllc_smac)) { rtnl_lock(); dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac); rtnl_unlock(); rc = -ENETUNREACH; if (!dev) goto out; - llc_ui->dev = dev; + llc->dev = dev; } /* bind to a specific sap, optional. */ if (!addr->sllc_ssap) { @@ -626,11 +448,11 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) struct sock *ask; rc = -EUSERS; /* can't get exclusive use of sap */ - if (!dev && llc_ui_mac_null(addr->sllc_mmac)) + if (!dev && llc_mac_null(addr->sllc_mmac)) goto out; memset(&laddr, 0, sizeof(laddr)); memset(&daddr, 0, sizeof(daddr)); - if (!llc_ui_mac_null(addr->sllc_mmac)) { + if (!llc_mac_null(addr->sllc_mmac)) { if (sk->type != SOCK_DGRAM) { rc = -EOPNOTSUPP; goto out; @@ -646,10 +468,16 @@ static int llc_ui_autobind(struct socket *sock, struct sockaddr_llc *addr) goto out; } } - memcpy(&llc_ui->addr, addr, sizeof(*addr)); - llc_ui->sap = sap; + llc->laddr.lsap = addr->sllc_ssap; + if (llc->dev) + memcpy(llc->laddr.mac, llc->dev->dev_addr, IFHWADDRLEN); + llc->daddr.lsap = addr->sllc_dsap; + memcpy(llc->daddr.mac, addr->sllc_dmac, IFHWADDRLEN); + memcpy(&llc->addr, addr, sizeof(llc->addr)); rc = sk->zapped = 0; llc_ui_insert_socket(sk); + /* assign new connection to it's SAP */ + llc_sap_assign_sock(sap, sk); out: return rc; } @@ -678,6 +506,7 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen) struct sock *sk = sock->sk; int rc = -EINVAL; + dprintk("%s: binding %02X\n", __FUNCTION__, addr->sllc_ssap); if (!sk->zapped || addrlen != sizeof(*addr)) goto out; rc = -EAFNOSUPPORT; @@ -711,9 +540,9 @@ static int llc_ui_shutdown(struct socket *sock, int how) rc = -EINVAL; if (how != 2) goto out; - rc = llc_ui_send_disc(sk); + rc = llc_send_disc(sk); if (!rc) - llc_ui_wait_for_disc(sk, 255); + rc = llc_ui_wait_for_disc(sk, sk->rcvtimeo); /* Wake up anyone sleeping in poll */ sk->state_change(sk); out: @@ -739,7 +568,7 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr, int addrlen, int flags) { struct sock *sk = sock->sk; - struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + struct llc_opt *llc = llc_sk(sk); struct sockaddr_llc *addr = (struct sockaddr_llc *)uaddr; struct net_device *dev; int rc = -EINVAL; @@ -757,14 +586,15 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr, if (rc) goto out; } - if (!llc_ui->dev) { + if (!llc->dev) { rtnl_lock(); dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac); rtnl_unlock(); if (!dev) goto out; + llc->dev = dev; } else - dev = llc_ui->dev; + dev = llc->dev; if (sk->type != SOCK_STREAM) goto out; rc = -EALREADY; @@ -772,14 +602,18 @@ static int llc_ui_connect(struct socket *sock, struct sockaddr *uaddr, goto out; sock->state = SS_CONNECTING; sk->state = TCP_SYN_SENT; - llc_ui->link = llc_ui_next_link_no(llc_ui->sap->laddr.lsap); - rc = llc_ui_send_conn(sk, llc_ui->sap, addr, dev, llc_ui->link); + llc->link = llc_ui_next_link_no(llc->sap->laddr.lsap); + rc = llc_establish_connection(sk, dev->dev_addr, + addr->sllc_dmac, addr->sllc_dsap); if (rc) { + dprintk("%s: llc_ui_send_conn failed :-(\n", __FUNCTION__); sock->state = SS_UNCONNECTED; sk->state = TCP_CLOSE; goto out; } - rc = llc_ui_wait_for_conn(sk, 255); + rc = llc_ui_wait_for_conn(sk, sk->rcvtimeo); + if (rc) + dprintk("%s: llc_ui_wait_for_conn failed=%d\n", __FUNCTION__, rc); out: release_sock(sk); return rc; @@ -802,7 +636,7 @@ static int llc_ui_listen(struct socket *sock, int backlog) if (sock->state != SS_UNCONNECTED) goto out; rc = -EOPNOTSUPP; - if (sk->type != SOCK_STREAM && sk->type != SOCK_SEQPACKET) + if (sk->type != SOCK_STREAM) goto out; rc = -EAGAIN; if (sk->zapped) @@ -810,8 +644,6 @@ static int llc_ui_listen(struct socket *sock, int backlog) rc = 0; if (!(unsigned)backlog) /* BSDism */ backlog = 1; - if ((unsigned)backlog > SOMAXCONN) - backlog = SOMAXCONN; sk->max_ack_backlog = backlog; if (sk->state != TCP_LISTEN) { sk->ack_backlog = 0; @@ -823,18 +655,43 @@ out: return rc; } -static int llc_ui_wait_for_disc(struct sock *sk, int seconds) +static int llc_ui_wait_for_disc(struct sock *sk, int timeout) { DECLARE_WAITQUEUE(wait, current); - int rc, timeout = seconds * HZ; + int rc; add_wait_queue_exclusive(sk->sleep, &wait); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); + rc = -ERESTARTSYS; + if (signal_pending(current)) + break; + rc = -EAGAIN; + if (!timeout) + break; rc = 0; - if (sk->state != TCP_CLOSE) + if (sk->state != TCP_CLOSE) { + release_sock(sk); timeout = schedule_timeout(timeout); - else + lock_sock(sk); + } else + break; + } + __set_current_state(TASK_RUNNING); + remove_wait_queue(sk->sleep, &wait); + return rc; +} + +static int llc_ui_wait_for_conn(struct sock *sk, int timeout) +{ + DECLARE_WAITQUEUE(wait, current); + int rc; + + add_wait_queue_exclusive(sk->sleep, &wait); + for (;;) { + __set_current_state(TASK_INTERRUPTIBLE); + rc = -EAGAIN; + if (sk->state == TCP_CLOSE) break; rc = -ERESTARTSYS; if (signal_pending(current)) @@ -842,31 +699,60 @@ static int llc_ui_wait_for_disc(struct sock *sk, int seconds) rc = -EAGAIN; if (!timeout) break; + rc = 0; + if (sk->state != TCP_ESTABLISHED) { + release_sock(sk); + timeout = schedule_timeout(timeout); + lock_sock(sk); + } else + break; } __set_current_state(TASK_RUNNING); remove_wait_queue(sk->sleep, &wait); return rc; } -static int llc_ui_wait_for_conn(struct sock *sk, int seconds) +static int llc_ui_wait_for_data(struct sock *sk, int timeout) { - struct llc_ui_opt *llc_ui = llc_ui_sk(sk); DECLARE_WAITQUEUE(wait, current); - int rc, timeout = seconds * HZ; + int rc = 0; add_wait_queue_exclusive(sk->sleep, &wait); for (;;) { __set_current_state(TASK_INTERRUPTIBLE); + if (sk->shutdown & RCV_SHUTDOWN) + break; + rc = -ERESTARTSYS; + if (signal_pending(current)) + break; + rc = -EAGAIN; + if (!timeout) + break; rc = 0; - if (sk->state != TCP_ESTABLISHED) + if (skb_queue_empty(&sk->receive_queue)) { + release_sock(sk); timeout = schedule_timeout(timeout); - if (sk->state == TCP_ESTABLISHED) { - if (!llc_ui->core_sk) - rc = -EAGAIN; + lock_sock(sk); + } else break; - } - rc = -EAGAIN; - if (sk->state == TCP_CLOSE) + } + __set_current_state(TASK_RUNNING); + remove_wait_queue(sk->sleep, &wait); + return rc; +} + +static int llc_ui_wait_for_busy_core(struct sock *sk, int timeout) +{ + DECLARE_WAITQUEUE(wait, current); + struct llc_opt *llc = llc_sk(sk); + int rc; + + add_wait_queue_exclusive(sk->sleep, &wait); + for (;;) { + dprintk("%s: looping...\n", __FUNCTION__); + __set_current_state(TASK_INTERRUPTIBLE); + rc = -ENOTCONN; + if (sk->shutdown & RCV_SHUTDOWN) break; rc = -ERESTARTSYS; if (signal_pending(current)) @@ -874,6 +760,13 @@ static int llc_ui_wait_for_conn(struct sock *sk, int seconds) rc = -EAGAIN; if (!timeout) break; + rc = 0; + if (llc_data_accept_state(llc->state) || llc->p_flag) { + release_sock(sk); + timeout = schedule_timeout(timeout); + lock_sock(sk); + } else + break; } __set_current_state(TASK_RUNNING); remove_wait_queue(sk->sleep, &wait); @@ -892,63 +785,48 @@ static int llc_ui_wait_for_conn(struct sock *sk, int seconds) static int llc_ui_accept(struct socket *sock, struct socket *newsock, int flags) { struct sock *sk = sock->sk, *newsk; - struct llc_ui_opt *llc_ui, *newllc_ui; - struct llc_opt *newllc_core; + struct llc_opt *llc, *newllc; struct sk_buff *skb; int rc = -EOPNOTSUPP; + dprintk("%s: accepting on %02X\n", __FUNCTION__, llc_sk(sk)->addr.sllc_ssap); lock_sock(sk); - if (sk->type != SOCK_SEQPACKET && sk->type != SOCK_STREAM) + if (sk->type != SOCK_STREAM) goto out; rc = -EINVAL; if (sock->state != SS_UNCONNECTED || sk->state != TCP_LISTEN) goto out; /* wait for a connection to arrive. */ - do { - skb = skb_dequeue(&sk->receive_queue); - if (!skb) { - rc = -EWOULDBLOCK; - if (flags & O_NONBLOCK) - goto out; - interruptible_sleep_on(sk->sleep); - rc = -ERESTARTSYS; - if (signal_pending(current)) - goto out; - } - } while (!skb); - - rc = -EINVAL; - if(!skb->sk) - goto frees; - /* attach connection to a new socket. */ - rc = llc_ui_create(newsock, sk->protocol); + rc = llc_ui_wait_for_data(sk, sk->rcvtimeo); if (rc) + goto out; + dprintk("%s: got a new connection on %02X\n", __FUNCTION__, llc_sk(sk)->addr.sllc_ssap); + skb = skb_dequeue(&sk->receive_queue); + rc = -EINVAL; + if (!skb->sk) goto frees; rc = 0; - newsk = newsock->sk; + newsk = skb->sk; + /* attach connection to a new socket. */ + llc_ui_sk_init(newsock, newsk); newsk->pair = NULL; - newsk->socket = newsock; - newsk->sleep = &newsock->wait; newsk->zapped = 0; newsk->state = TCP_ESTABLISHED; newsock->state = SS_CONNECTED; - llc_ui = llc_ui_sk(sk); - newllc_ui = llc_ui_sk(newsk); - newllc_ui->sap = llc_ui->sap; - newllc_ui->dev = llc_ui->dev; - newllc_ui->core_sk = skb->sk; - newllc_core = llc_sk(newllc_ui->core_sk); - newllc_ui->link = newllc_core->link; - newllc_core->handler = newsk; - memcpy(&newllc_ui->addr, &llc_ui->addr, sizeof(newllc_ui->addr)); - memcpy(newllc_ui->addr.sllc_dmac, newllc_core->daddr.mac, IFHWADDRLEN); - newllc_ui->addr.sllc_dsap = newllc_core->daddr.lsap; + llc = llc_sk(sk); + newllc = llc_sk(newsk); + memcpy(&newllc->addr, &llc->addr, sizeof(newllc->addr)); + memcpy(newllc->addr.sllc_dmac, newllc->daddr.mac, IFHWADDRLEN); + newllc->addr.sllc_dsap = newllc->daddr.lsap; + newllc->link = llc_ui_next_link_no(newllc->laddr.lsap); /* put original socket back into a clean listen state. */ sk->state = TCP_LISTEN; sk->ack_backlog--; llc_ui_insert_socket(newsk); skb->sk = NULL; + dprintk("%s: ok success on %02X, client on %02X\n", __FUNCTION__, + llc_sk(sk)->addr.sllc_ssap, newllc->addr.sllc_dsap); frees: kfree_skb(skb); out: @@ -973,12 +851,21 @@ static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, int size, struct sock *sk = sock->sk; struct sockaddr_llc *uaddr = (struct sockaddr_llc *)msg->msg_name; struct sk_buff *skb; - int rc = -ENOMEM, copied = 0; + int rc = -ENOMEM, copied = 0, timeout; int noblock = flags & MSG_DONTWAIT; + dprintk("%s: receiving in %02X from %02X\n", __FUNCTION__, + llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap); lock_sock(sk); - skb = skb_recv_datagram(sk, flags, noblock, &rc); - if (!skb) + timeout = sock_rcvtimeo(sk, noblock); + rc = llc_ui_wait_for_data(sk, timeout); + if (rc) { + dprintk("%s: llc_ui_wait_for_data failed recv in %02X from %02X\n", + __FUNCTION__, llc_sk(sk)->laddr.lsap, llc_sk(sk)->daddr.lsap); + goto out; + } + skb = skb_dequeue(&sk->receive_queue); + if (!skb) /* shutdown */ goto out; copied = skb->len; if (copied > size) { @@ -992,7 +879,7 @@ static int llc_ui_recvmsg(struct socket *sock, struct msghdr *msg, int size, memcpy(uaddr, llc_ui_skb_cb(skb), sizeof(*uaddr)); msg->msg_namelen = sizeof(*uaddr); dgram_free: - skb_free_datagram(sk, skb); /* Free the datagram. */ + kfree_skb(skb); out: release_sock(sk); return rc ? : copied; @@ -1012,24 +899,23 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len, struct scm_cookie *scm) { struct sock *sk = sock->sk; - struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + struct llc_opt *llc = llc_sk(sk); struct sockaddr_llc *addr = (struct sockaddr_llc *)msg->msg_name; int flags = msg->msg_flags; + int noblock = flags & MSG_DONTWAIT; struct net_device *dev; struct sk_buff *skb; - int rc = -EOPNOTSUPP, size = 0; + int rc = -EINVAL, size = 0; + dprintk("%s: sending from %02X to %02X\n", __FUNCTION__, llc->laddr.lsap, llc->daddr.lsap); lock_sock(sk); - if (flags & ~MSG_DONTWAIT) - goto release; - rc = -EINVAL; if (addr) { if (msg->msg_namelen < sizeof(*addr)) goto release; } else { - if (llc_ui_addr_null(&llc_ui->addr)) + if (llc_ui_addr_null(&llc->addr)) goto release; - addr = &llc_ui->addr; + addr = &llc->addr; } /* must bind connection to sap if user hasn't done it. */ if (sk->zapped) { @@ -1038,7 +924,7 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len, if (rc) goto release; } - if (!llc_ui->dev) { + if (!llc->dev) { rtnl_lock(); dev = dev_getbyhwaddr(addr->sllc_arphrd, addr->sllc_smac); rtnl_unlock(); @@ -1046,12 +932,12 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len, if (!dev) goto release; } else - dev = llc_ui->dev; + dev = llc->dev; size = dev->hard_header_len + len + llc_ui_header_len(sk, addr); rc = -EMSGSIZE; if (size > dev->mtu) goto release; - skb = sock_alloc_send_skb(sk, size, flags & MSG_DONTWAIT, &rc); + skb = sock_alloc_send_skb(sk, size, noblock, &rc); if (!skb) goto release; skb->sk = sk; @@ -1059,30 +945,32 @@ static int llc_ui_sendmsg(struct socket *sock, struct msghdr *msg, int len, skb_reserve(skb, dev->hard_header_len + llc_ui_header_len(sk, addr)); rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len); if (rc) - goto release; + goto out; if (addr->sllc_test) { - rc = llc_ui_send_llc1(llc_ui->sap, skb, addr, LLC_TEST_PRIM); + llc_build_and_send_test_pkt(llc->sap, skb, addr); goto out; } if (addr->sllc_xid) { - rc = llc_ui_send_llc1(llc_ui->sap, skb, addr, LLC_XID_PRIM); + llc_build_and_send_xid_pkt(llc->sap, skb, addr); goto out; } if (sk->type == SOCK_DGRAM || addr->sllc_ua) { - rc = llc_ui_send_llc1(llc_ui->sap, skb, addr, LLC_DATAUNIT_PRIM); + llc_build_and_send_ui_pkt(llc->sap, skb, addr); goto out; } rc = -ENOPROTOOPT; if (!(sk->type == SOCK_STREAM && !addr->sllc_ua)) goto out; - rc = -ENOTCONN; - if (!llc_ui->core_sk) - goto out; - rc = llc_ui_send_data(llc_ui->sap, sk, skb, addr); + rc = llc_ui_send_data(sk, skb, addr, noblock); + if (rc) + dprintk("%s: llc_ui_send_data failed: %d\n", __FUNCTION__, rc); out: if (rc) - skb_free_datagram(sk, skb); + kfree_skb(skb); release: + if (rc) + dprintk("%s: failed sending from %02X to %02X: %d\n", + __FUNCTION__, llc->laddr.lsap, llc->daddr.lsap, rc); release_sock(sk); return rc ? : len; } @@ -1101,7 +989,7 @@ static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr, { struct sockaddr_llc sllc; struct sock *sk = sock->sk; - struct llc_ui_opt *llc_ui = llc_ui_sk(sk); + struct llc_opt *llc = llc_sk(sk); int rc = 0; lock_sock(sk); @@ -1113,20 +1001,19 @@ static int llc_ui_getname(struct socket *sock, struct sockaddr *uaddr, rc = -ENOTCONN; if (sk->state != TCP_ESTABLISHED) goto out; - if(llc_ui->dev) - sllc.sllc_arphrd = llc_ui->dev->type; - sllc.sllc_dsap = llc_sk(llc_ui->core_sk)->daddr.lsap; - memcpy(&sllc.sllc_dmac, &llc_sk(llc_ui->core_sk)->daddr.mac, - IFHWADDRLEN); + if(llc->dev) + sllc.sllc_arphrd = llc->dev->type; + sllc.sllc_dsap = llc->daddr.lsap; + memcpy(&sllc.sllc_dmac, &llc->daddr.mac, IFHWADDRLEN); } else { rc = -EINVAL; - if (!llc_ui->sap) + if (!llc->sap) goto out; - sllc.sllc_ssap = llc_ui->sap->laddr.lsap; + sllc.sllc_ssap = llc->sap->laddr.lsap; - if (llc_ui->dev) { - sllc.sllc_arphrd = llc_ui->dev->type; - memcpy(&sllc.sllc_smac, &llc_ui->dev->dev_addr, + if (llc->dev) { + sllc.sllc_arphrd = llc->dev->type; + memcpy(&sllc.sllc_smac, &llc->dev->dev_addr, IFHWADDRLEN); } } @@ -1166,61 +1053,56 @@ static int llc_ui_setsockopt(struct socket *sock, int level, int optname, char *optval, int optlen) { struct sock *sk = sock->sk; - struct llc_ui_opt *llc_ui = llc_ui_sk(sk); - struct llc_opt *llc_core; + struct llc_opt *llc = llc_sk(sk); int rc = -EINVAL, opt; lock_sock(sk); if (level != SOL_LLC || optlen != sizeof(int)) goto out; - rc = -ENOTCONN; - if (!llc_ui->core_sk) - goto out; rc = get_user(opt, (int *)optval); if (rc) goto out; rc = -EINVAL; - llc_core = llc_sk(llc_ui->core_sk); switch (optname) { case LLC_OPT_RETRY: if (opt > LLC_OPT_MAX_RETRY) goto out; - llc_core->n2 = opt; + llc->n2 = opt; break; case LLC_OPT_SIZE: if (opt > LLC_OPT_MAX_SIZE) goto out; - llc_core->n1 = opt; + llc->n1 = opt; break; case LLC_OPT_ACK_TMR_EXP: if (opt > LLC_OPT_MAX_ACK_TMR_EXP) goto out; - llc_core->ack_timer.expire = opt; + llc->ack_timer.expire = opt; break; case LLC_OPT_P_TMR_EXP: if (opt > LLC_OPT_MAX_P_TMR_EXP) goto out; - llc_core->pf_cycle_timer.expire = opt; + llc->pf_cycle_timer.expire = opt; break; case LLC_OPT_REJ_TMR_EXP: if (opt > LLC_OPT_MAX_REJ_TMR_EXP) goto out; - llc_core->rej_sent_timer.expire = opt; + llc->rej_sent_timer.expire = opt; break; case LLC_OPT_BUSY_TMR_EXP: if (opt > LLC_OPT_MAX_BUSY_TMR_EXP) goto out; - llc_core->busy_state_timer.expire = opt; + llc->busy_state_timer.expire = opt; break; case LLC_OPT_TX_WIN: if (opt > LLC_OPT_MAX_WIN) goto out; - llc_core->k = opt; + llc->k = opt; break; case LLC_OPT_RX_WIN: if (opt > LLC_OPT_MAX_WIN) goto out; - llc_core->rw = opt; + llc->rw = opt; break; default: rc = -ENOPROTOOPT; @@ -1246,40 +1128,35 @@ static int llc_ui_getsockopt(struct socket *sock, int level, int optname, char *optval, int *optlen) { struct sock *sk = sock->sk; - struct llc_ui_opt *llc_ui = llc_ui_sk(sk); - struct llc_opt *llc_core; + struct llc_opt *llc = llc_sk(sk); int val = 0, len = 0, rc = -EINVAL; lock_sock(sk); if (level != SOL_LLC) goto out; - rc = -ENOTCONN; - if (!llc_ui->core_sk) - goto out; rc = get_user(len, optlen); if (rc) goto out; rc = -EINVAL; if (len != sizeof(int)) goto out; - llc_core = llc_sk(llc_ui->core_sk); switch (optname) { case LLC_OPT_RETRY: - val = llc_core->n2; break; + val = llc->n2; break; case LLC_OPT_SIZE: - val = llc_core->n1; break; + val = llc->n1; break; case LLC_OPT_ACK_TMR_EXP: - val = llc_core->ack_timer.expire; break; + val = llc->ack_timer.expire; break; case LLC_OPT_P_TMR_EXP: - val = llc_core->pf_cycle_timer.expire; break; + val = llc->pf_cycle_timer.expire; break; case LLC_OPT_REJ_TMR_EXP: - val = llc_core->rej_sent_timer.expire; break; + val = llc->rej_sent_timer.expire; break; case LLC_OPT_BUSY_TMR_EXP: - val = llc_core->busy_state_timer.expire; break; + val = llc->busy_state_timer.expire; break; case LLC_OPT_TX_WIN: - val = llc_core->k; break; + val = llc->k; break; case LLC_OPT_RX_WIN: - val = llc_core->rw; break; + val = llc->rw; break; default: rc = -ENOPROTOOPT; goto out; @@ -1302,7 +1179,7 @@ static void llc_ui_ind_test(struct llc_prim_if_block *prim) { struct llc_prim_test *prim_data = &prim->data->test; struct sk_buff *skb = prim_data->skb; - struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb); + struct sockaddr_llc *addr = llc_ui_skb_cb(skb); struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr, &prim_data->saddr, skb->dev); if (!sk) @@ -1310,15 +1187,15 @@ static void llc_ui_ind_test(struct llc_prim_if_block *prim) if (sk->state == TCP_LISTEN) goto out_put; /* save primitive for use by the user. */ - llc_ui->sllc_family = AF_LLC; - llc_ui->sllc_arphrd = skb->dev->type; - llc_ui->sllc_test = 1; - llc_ui->sllc_xid = 0; - llc_ui->sllc_ua = 0; - llc_ui->sllc_dsap = prim_data->daddr.lsap; - memcpy(llc_ui->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN); - llc_ui->sllc_ssap = prim_data->saddr.lsap; - memcpy(llc_ui->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN); + addr->sllc_family = AF_LLC; + addr->sllc_arphrd = skb->dev->type; + addr->sllc_test = 1; + addr->sllc_xid = 0; + addr->sllc_ua = 0; + addr->sllc_dsap = prim_data->daddr.lsap; + memcpy(addr->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN); + addr->sllc_ssap = prim_data->saddr.lsap; + memcpy(addr->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN); /* queue skb to the user. */ if (sock_queue_rcv_skb(sk, skb)) kfree_skb(skb); @@ -1337,7 +1214,7 @@ static void llc_ui_ind_xid(struct llc_prim_if_block *prim) { struct llc_prim_xid *prim_data = &prim->data->xid; struct sk_buff *skb = prim_data->skb; - struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb); + struct sockaddr_llc *addr = llc_ui_skb_cb(skb); struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr, &prim_data->saddr, skb->dev); if (!sk) @@ -1345,15 +1222,15 @@ static void llc_ui_ind_xid(struct llc_prim_if_block *prim) if (sk->state == TCP_LISTEN) goto out_put; /* save primitive for use by the user. */ - llc_ui->sllc_family = AF_LLC; - llc_ui->sllc_arphrd = 0; - llc_ui->sllc_test = 0; - llc_ui->sllc_xid = 1; - llc_ui->sllc_ua = 0; - llc_ui->sllc_dsap = prim_data->daddr.lsap; - memcpy(llc_ui->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN); - llc_ui->sllc_ssap = prim_data->saddr.lsap; - memcpy(llc_ui->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN); + addr->sllc_family = AF_LLC; + addr->sllc_arphrd = 0; + addr->sllc_test = 0; + addr->sllc_xid = 1; + addr->sllc_ua = 0; + addr->sllc_dsap = prim_data->daddr.lsap; + memcpy(addr->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN); + addr->sllc_ssap = prim_data->saddr.lsap; + memcpy(addr->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN); /* queue skb to the user. */ if (sock_queue_rcv_skb(sk, skb)) kfree_skb(skb); @@ -1372,7 +1249,7 @@ static void llc_ui_ind_dataunit(struct llc_prim_if_block *prim) { struct llc_prim_unit_data *prim_data = &prim->data->udata; struct sk_buff *skb = prim_data->skb; - struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb); + struct sockaddr_llc *addr = llc_ui_skb_cb(skb); struct sock *sk = llc_ui_find_sk_by_addr(&prim_data->daddr, &prim_data->saddr, skb->dev); if (!sk) @@ -1380,88 +1257,15 @@ static void llc_ui_ind_dataunit(struct llc_prim_if_block *prim) if (sk->state == TCP_LISTEN) goto out_put; /* save primitive for use by the user. */ - llc_ui->sllc_family = AF_LLC; - llc_ui->sllc_arphrd = skb->dev->type; - llc_ui->sllc_test = 0; - llc_ui->sllc_xid = 0; - llc_ui->sllc_ua = 1; - llc_ui->sllc_dsap = prim_data->daddr.lsap; - memcpy(llc_ui->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN); - llc_ui->sllc_ssap = prim_data->saddr.lsap; - memcpy(llc_ui->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN); - /* queue skb to the user. */ - if (sock_queue_rcv_skb(sk, skb)) - kfree_skb(skb); -out_put: - sock_put(sk); -out:; -} - -/** - * llc_ui_ind_conn - handle CONNECT indication - * @prim: Primitive block provided by the llc layer. - * - * handle CONNECT indication. - */ -static void llc_ui_ind_conn(struct llc_prim_if_block *prim) -{ - struct llc_prim_conn *prim_data = &prim->data->conn; - struct sock* sk; - struct sk_buff *skb2; - - llc_sk(prim_data->sk)->laddr.lsap = prim->sap->laddr.lsap; - sk = llc_ui_find_sk_by_addr(&llc_sk(prim_data->sk)->laddr, - &prim_data->saddr, prim_data->dev); - if (!sk) - goto out; - if (sk->type != SOCK_STREAM || sk->state != TCP_LISTEN) - goto out_put; - if (prim->data->conn.status) - goto out_put; /* bad status. */ - /* give this connection a link number. */ - llc_sk(prim_data->sk)->link = - llc_ui_next_link_no(llc_sk(prim_data->sk)->laddr.lsap); - skb2 = alloc_skb(0, GFP_ATOMIC); - if (!skb2) - goto out_put; - skb2->sk = prim_data->sk; - skb_queue_tail(&sk->receive_queue, skb2); - sk->state_change(sk); -out_put: - sock_put(sk); -out:; -} - -/** - * llc_ui_ind_data - handle DATA indication - * @prim: Primitive block provided by the llc layer. - * - * handle CONNECT indication. - */ -static void llc_ui_ind_data(struct llc_prim_if_block *prim) -{ - struct llc_prim_data *prim_data = &prim->data->data; - struct sk_buff *skb = prim_data->skb; - struct sockaddr_llc *llc_ui = llc_ui_skb_cb(skb); - struct sock* sk = llc_sk(prim_data->sk)->handler; - - if (!sk) - goto out; - sock_hold(sk); - if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED) - goto out_put; - /* save primitive for use by the user. */ - llc_ui->sllc_family = AF_LLC; - llc_ui->sllc_arphrd = skb->dev->type; - llc_ui->sllc_test = 0; - llc_ui->sllc_xid = 0; - llc_ui->sllc_ua = 0; - llc_ui->sllc_dsap = llc_ui_sk(sk)->sap->laddr.lsap; - memcpy(llc_ui->sllc_dmac, llc_sk(prim_data->sk)->laddr.mac, - IFHWADDRLEN); - llc_ui->sllc_ssap = llc_sk(prim_data->sk)->daddr.lsap; - memcpy(llc_ui->sllc_smac, llc_sk(prim_data->sk)->daddr.mac, - IFHWADDRLEN); + addr->sllc_family = AF_LLC; + addr->sllc_arphrd = skb->dev->type; + addr->sllc_test = 0; + addr->sllc_xid = 0; + addr->sllc_ua = 1; + addr->sllc_dsap = prim_data->daddr.lsap; + memcpy(addr->sllc_dmac, prim_data->daddr.mac, IFHWADDRLEN); + addr->sllc_ssap = prim_data->saddr.lsap; + memcpy(addr->sllc_smac, prim_data->saddr.mac, IFHWADDRLEN); /* queue skb to the user. */ if (sock_queue_rcv_skb(sk, skb)) kfree_skb(skb); @@ -1471,35 +1275,6 @@ out:; } /** - * llc_ui_ind_disc - handle DISC indication - * @prim: Primitive block provided by the llc layer. - * - * handle DISC indication. - */ -static void llc_ui_ind_disc(struct llc_prim_if_block *prim) -{ - struct llc_prim_disc *prim_data = &prim->data->disc; - struct sock* sk = llc_sk(prim_data->sk)->handler; - - if (!sk) - goto out; - sock_hold(sk); - if (sk->type != SOCK_STREAM || sk->state != TCP_ESTABLISHED) - goto out_put; - llc_ui_sk(sk)->core_sk = NULL; - sk->shutdown = SHUTDOWN_MASK; - sk->socket->state = SS_UNCONNECTED; - sk->state = TCP_CLOSE; - if (!sk->dead) { - sk->state_change(sk); - sk->dead = 1; - } -out_put: - sock_put(sk); -out:; -} - -/** * llc_ui_indicate - LLC user interface hook into the LLC layer. * @prim: Primitive block provided by the llc layer. * @@ -1517,92 +1292,24 @@ static int llc_ui_indicate(struct llc_prim_if_block *prim) case LLC_DATAUNIT_PRIM: llc_ui_ind_dataunit(prim); break; case LLC_CONN_PRIM: - llc_ui_ind_conn(prim); break; + dprintk("%s: shouldn't happen, LLC_CONN_PRIM " + "is gone for ->ind()...\n", __FUNCTION__); + break; case LLC_DATA_PRIM: - llc_ui_ind_data(prim); break; + dprintk("%s: shouldn't happen, LLC_DATA_PRIM " + "is gone for ->ind()...\n", __FUNCTION__); + break; case LLC_DISC_PRIM: - llc_ui_ind_disc(prim); break; + dprintk("%s: shouldn't happen, LLC_DISC_PRIM " + "is gone for ->ind()...\n", __FUNCTION__); + break; case LLC_RESET_PRIM: - case LLC_FLOWCONTROL_PRIM: default: break; } return 0; } /** - * llc_ui_conf_conn - handle CONN confirm. - * @prim: Primitive block provided by the llc layer. - * - * handle CONN confirm. - */ -static void llc_ui_conf_conn(struct llc_prim_if_block *prim) -{ - struct llc_prim_conn *prim_data = &prim->data->conn; - struct llc_opt *llc_core = llc_sk(prim_data->sk); - struct sock* sk = llc_core->handler; - struct llc_ui_opt *llc_ui = llc_ui_sk(sk); - - if (!sk) - goto out; - sock_hold(sk); - if (sk->type != SOCK_STREAM || sk->state != TCP_SYN_SENT) - goto out_put; - if (!prim->data->conn.status) { - sk->socket->state = SS_CONNECTED; - sk->state = TCP_ESTABLISHED; - llc_ui->core_sk = prim_data->sk; - } else { - sk->socket->state = SS_UNCONNECTED; - sk->state = TCP_CLOSE; - llc_ui->core_sk = NULL; - } - sk->state_change(sk); -out_put: - sock_put(sk); -out:; -} - -/** - * llc_ui_conf_data - handle DATA confirm. - * @prim: Primitive block provided by the llc layer. - * - * handle DATA confirm. - */ -static void llc_ui_conf_data(struct llc_prim_if_block *prim) -{ - struct llc_prim_data *prim_data = &prim->data->data; - struct sock* sk = llc_sk(prim_data->sk)->handler; - - if (sk) - wake_up(sk->sleep); -} - -/** - * llc_ui_conf_disc - handle DISC confirm. - * @prim: Primitive block provided by the llc layer. - * - * handle DISC confirm. - */ -static void llc_ui_conf_disc(struct llc_prim_if_block *prim) -{ - struct llc_prim_disc *prim_data = &prim->data->disc; - struct sock* sk = llc_sk(prim_data->sk)->handler; - - if (!sk) - goto out; - sock_hold(sk); - if (sk->type != SOCK_STREAM || sk->state != TCP_CLOSING) - goto out_put; - llc_ui_sk(sk)->core_sk = NULL; - sk->socket->state = SS_UNCONNECTED; - sk->state = TCP_CLOSE; - sk->state_change(sk); -out_put: - sock_put(sk); -out:; -} - -/** * llc_ui_confirm - LLC user interface hook into the LLC layer * @prim: Primitive block provided by the llc layer. * @@ -1614,14 +1321,20 @@ static int llc_ui_confirm(struct llc_prim_if_block *prim) { switch (prim->prim) { case LLC_CONN_PRIM: - llc_ui_conf_conn(prim); break; + dprintk("%s: shouldn't happen, LLC_CONN_PRIM " + "is gone for ->conf()...\n", __FUNCTION__); + break; case LLC_DATA_PRIM: - llc_ui_conf_data(prim); break; + dprintk("%s: shouldn't happen, LLC_DATA_PRIM " + "is gone for ->conf()...\n", __FUNCTION__); + break; case LLC_DISC_PRIM: - llc_ui_conf_disc(prim); break; + dprintk("%s: shouldn't happen, LLC_DISC_PRIM " + "is gone for ->conf()...\n", __FUNCTION__); + break; case LLC_RESET_PRIM: break; default: - printk(KERN_ERR "%s: unknown prim %d\n", __FUNCTION__, + printk(KERN_ERR "%s: prim not supported%d\n", __FUNCTION__, prim->prim); break; } @@ -1651,46 +1364,42 @@ static int llc_ui_get_info(char *buffer, char **start, off_t offset, int length) off_t pos = 0; off_t begin = 0; struct sock *s; - int len = sprintf(buffer, "SocketID SKt Mc local_mac_sap\t " - "remote_mac_sap\t tx_queue rx_queue st uid " - "link_no\n"); + int len = sprintf(buffer, "SKt Mc local_mac_sap " + "remote_mac_sap tx_queue rx_queue st uid " + "link\n"); /* Output the LLC socket data for the /proc filesystem */ read_lock_bh(&llc_ui_sockets_lock); for (s = llc_ui_sockets; s; s = s->next) { - struct llc_ui_opt *llc_ui = llc_ui_sk(s); - len += sprintf(buffer + len, "%p %02X %02X ", s, s->type, - !llc_ui_mac_null(llc_ui->addr.sllc_mmac)); - if (llc_ui->sap) { - if (llc_ui->dev && - llc_ui_mac_null(llc_ui->addr.sllc_mmac)) + struct llc_opt *llc = llc_sk(s); + + len += sprintf(buffer + len, "%2X %2X ", s->type, + !llc_mac_null(llc->addr.sllc_mmac)); + if (llc->sap) { + if (llc->dev && llc_mac_null(llc->addr.sllc_mmac)) llc_ui_format_mac(buffer + len, - llc_ui->dev->dev_addr); + llc->dev->dev_addr); else { - if (!llc_ui_mac_null(llc_ui->addr.sllc_mmac)) + if (!llc_mac_null(llc->addr.sllc_mmac)) llc_ui_format_mac(buffer + len, - llc_ui->addr.sllc_mmac); + llc->addr.sllc_mmac); else sprintf(buffer + len, "00:00:00:00:00:00"); } len += MAC_FORMATTED_SIZE; len += sprintf(buffer + len, "@%02X ", - llc_ui->sap->laddr.lsap); + llc->sap->laddr.lsap); } else len += sprintf(buffer + len, "00:00:00:00:00:00@00 "); - llc_ui_format_mac(buffer + len, llc_ui->addr.sllc_dmac); + llc_ui_format_mac(buffer + len, llc->addr.sllc_dmac); len += MAC_FORMATTED_SIZE; len += sprintf(buffer + len, - "@%02X %08d:%08d %02d %-3d ", - llc_ui->addr.sllc_dsap, + "@%02X %8d %8d %2d %-3d ", + llc->addr.sllc_dsap, atomic_read(&s->wmem_alloc), atomic_read(&s->rmem_alloc), s->state, SOCK_INODE(s->socket)->i_uid); - if (llc_ui->core_sk) - len += sprintf(buffer + len, "%-7d\n", - llc_sk(llc_ui->core_sk)->link); - else - len += sprintf(buffer + len, "no_link\n"); + len += sprintf(buffer + len, "%-4d\n", llc->link); /* Are we still dumping unwanted data then discard the record */ pos = begin + len; @@ -1741,7 +1450,7 @@ static struct proto_ops SOCKOPS_WRAPPED(llc_ui_ops) = { SOCKOPS_WRAP(llc_ui, PF_LLC); static char llc_ui_banner[] __initdata = - KERN_INFO "NET4.0 IEEE 802.2 User Interface SAPs, Jay Schulist, 2001\n"; + KERN_INFO "NET4.0 IEEE 802.2 BSD sockets, Jay Schulist, 2001, Arnaldo C. Melo, 2002\n"; int __init llc_ui_init(void) { |
