Commit 703071b5 authored by Linus Torvalds's avatar Linus Torvalds

Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6:
  [SUNGEM]: Fix MAC address setting when interface is up.
  [IPV4] fib_trie: Document locking.
  [NET]: Correct accept(2) recovery after sock_attach_fd()
  [PPP]: Don't leak an sk_buff on interface destruction.
  [NET_SCHED]: Fix ingress locking
  [NET_SCHED]: cls_basic: fix NULL pointer dereference
  [DCCP]: make dccp_write_xmit_timer() static again
  [TG3]: Update version and reldate.
  [TG3]: Exit irq handler during chip reset.
  [TG3]: Eliminate the unused TG3_FLAG_SPLIT_MODE flag.
  [IPV6]: Fix routing round-robin locking.
  [DECNet] fib: Fix out of bound access of dn_fib_props[]
  [IPv4] fib: Fix out of bound access of fib_props[]
  [NET] AX.25 Kconfig and docs updates and fixes
  [NET]: Fix neighbour destructor handling.
  [NET]: Fix fib_rules compatibility breakage
  [SCTP]: Update SCTP Maintainers entry
  [NET]: remove unused header file: drivers/net/wan/lmc/lmc_media.h
parents 6288c338 09c72ec8
To use the amateur radio protocols within Linux you will need to get a To use the amateur radio protocols within Linux you will need to get a
suitable copy of the AX.25 Utilities. More detailed information about these suitable copy of the AX.25 Utilities. More detailed information about
and associated programs can be found on http://zone.pspt.fi/~jsn/. AX.25, NET/ROM and ROSE, associated programs and and utilities can be
found on http://www.linux-ax25.org.
For more information about the AX.25, NET/ROM and ROSE protocol stacks, see
the AX25-HOWTO written by Terry Dawson <terry@perf.no.itg.telstra.com.au>
who is also the AX.25 Utilities maintainer.
There is an active mailing list for discussing Linux amateur radio matters There is an active mailing list for discussing Linux amateur radio matters
called linux-hams. To subscribe to it, send a message to called linux-hams@vger.kernel.org. To subscribe to it, send a message to
majordomo@vger.kernel.org with the words "subscribe linux-hams" in the body majordomo@vger.kernel.org with the words "subscribe linux-hams" in the body
of the message, the subject field is ignored. of the message, the subject field is ignored. You don't need to be
subscribed to post but of course that means you might miss an answer.
Jonathan G4KLX
g4klx@g4klx.demon.co.uk
...@@ -2928,9 +2928,12 @@ L: linux-scsi@vger.kernel.org ...@@ -2928,9 +2928,12 @@ L: linux-scsi@vger.kernel.org
S: Maintained S: Maintained
SCTP PROTOCOL SCTP PROTOCOL
P: Vlad Yasevich
M: vladislav.yasevich@hp.com
P: Sridhar Samudrala P: Sridhar Samudrala
M: sri@us.ibm.com M: sri@us.ibm.com
L: lksctp-developers@lists.sourceforge.net L: lksctp-developers@lists.sourceforge.net
W: http://lksctp.sourceforge.net
S: Supported S: Supported
SCx200 CPU SUPPORT SCx200 CPU SUPPORT
......
...@@ -814,7 +814,7 @@ static void ipoib_set_mcast_list(struct net_device *dev) ...@@ -814,7 +814,7 @@ static void ipoib_set_mcast_list(struct net_device *dev)
queue_work(ipoib_workqueue, &priv->restart_task); queue_work(ipoib_workqueue, &priv->restart_task);
} }
static void ipoib_neigh_destructor(struct neighbour *n) static void ipoib_neigh_cleanup(struct neighbour *n)
{ {
struct ipoib_neigh *neigh; struct ipoib_neigh *neigh;
struct ipoib_dev_priv *priv = netdev_priv(n->dev); struct ipoib_dev_priv *priv = netdev_priv(n->dev);
...@@ -822,7 +822,7 @@ static void ipoib_neigh_destructor(struct neighbour *n) ...@@ -822,7 +822,7 @@ static void ipoib_neigh_destructor(struct neighbour *n)
struct ipoib_ah *ah = NULL; struct ipoib_ah *ah = NULL;
ipoib_dbg(priv, ipoib_dbg(priv,
"neigh_destructor for %06x " IPOIB_GID_FMT "\n", "neigh_cleanup for %06x " IPOIB_GID_FMT "\n",
IPOIB_QPN(n->ha), IPOIB_QPN(n->ha),
IPOIB_GID_RAW_ARG(n->ha + 4)); IPOIB_GID_RAW_ARG(n->ha + 4));
...@@ -874,7 +874,7 @@ void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh) ...@@ -874,7 +874,7 @@ void ipoib_neigh_free(struct net_device *dev, struct ipoib_neigh *neigh)
static int ipoib_neigh_setup_dev(struct net_device *dev, struct neigh_parms *parms) static int ipoib_neigh_setup_dev(struct net_device *dev, struct neigh_parms *parms)
{ {
parms->neigh_destructor = ipoib_neigh_destructor; parms->neigh_cleanup = ipoib_neigh_cleanup;
return 0; return 0;
} }
......
...@@ -2544,6 +2544,9 @@ static void ppp_destroy_interface(struct ppp *ppp) ...@@ -2544,6 +2544,9 @@ static void ppp_destroy_interface(struct ppp *ppp)
ppp->active_filter = NULL; ppp->active_filter = NULL;
#endif /* CONFIG_PPP_FILTER */ #endif /* CONFIG_PPP_FILTER */
if (ppp->xmit_pending)
kfree_skb(ppp->xmit_pending);
kfree(ppp); kfree(ppp);
} }
......
...@@ -2530,6 +2530,35 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev) ...@@ -2530,6 +2530,35 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev)
return &gp->net_stats; return &gp->net_stats;
} }
static int gem_set_mac_address(struct net_device *dev, void *addr)
{
struct sockaddr *macaddr = (struct sockaddr *) addr;
struct gem *gp = dev->priv;
unsigned char *e = &dev->dev_addr[0];
if (!is_valid_ether_addr(macaddr->sa_data))
return -EADDRNOTAVAIL;
if (!netif_running(dev) || !netif_device_present(dev)) {
/* We'll just catch it later when the
* device is up'd or resumed.
*/
memcpy(dev->dev_addr, macaddr->sa_data, dev->addr_len);
return 0;
}
mutex_lock(&gp->pm_mutex);
memcpy(dev->dev_addr, macaddr->sa_data, dev->addr_len);
if (gp->running) {
writel((e[4] << 8) | e[5], gp->regs + MAC_ADDR0);
writel((e[2] << 8) | e[3], gp->regs + MAC_ADDR1);
writel((e[0] << 8) | e[1], gp->regs + MAC_ADDR2);
}
mutex_unlock(&gp->pm_mutex);
return 0;
}
static void gem_set_multicast(struct net_device *dev) static void gem_set_multicast(struct net_device *dev)
{ {
struct gem *gp = dev->priv; struct gem *gp = dev->priv;
...@@ -3122,6 +3151,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev, ...@@ -3122,6 +3151,7 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
dev->change_mtu = gem_change_mtu; dev->change_mtu = gem_change_mtu;
dev->irq = pdev->irq; dev->irq = pdev->irq;
dev->dma = 0; dev->dma = 0;
dev->set_mac_address = gem_set_mac_address;
#ifdef CONFIG_NET_POLL_CONTROLLER #ifdef CONFIG_NET_POLL_CONTROLLER
dev->poll_controller = gem_poll_controller; dev->poll_controller = gem_poll_controller;
#endif #endif
......
...@@ -64,8 +64,8 @@ ...@@ -64,8 +64,8 @@
#define DRV_MODULE_NAME "tg3" #define DRV_MODULE_NAME "tg3"
#define PFX DRV_MODULE_NAME ": " #define PFX DRV_MODULE_NAME ": "
#define DRV_MODULE_VERSION "3.74" #define DRV_MODULE_VERSION "3.75"
#define DRV_MODULE_RELDATE "February 20, 2007" #define DRV_MODULE_RELDATE "March 23, 2007"
#define TG3_DEF_MAC_MODE 0 #define TG3_DEF_MAC_MODE 0
#define TG3_DEF_RX_MODE 0 #define TG3_DEF_RX_MODE 0
...@@ -3568,32 +3568,34 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id) ...@@ -3568,32 +3568,34 @@ static irqreturn_t tg3_interrupt(int irq, void *dev_id)
* Reading the PCI State register will confirm whether the * Reading the PCI State register will confirm whether the
* interrupt is ours and will flush the status block. * interrupt is ours and will flush the status block.
*/ */
if ((sblk->status & SD_STATUS_UPDATED) || if (unlikely(!(sblk->status & SD_STATUS_UPDATED))) {
!(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) { if ((tp->tg3_flags & TG3_FLAG_CHIP_RESETTING) ||
/* (tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) {
* Writing any value to intr-mbox-0 clears PCI INTA# and handled = 0;
* chip-internal interrupt pending events.
* Writing non-zero to intr-mbox-0 additional tells the
* NIC to stop sending us irqs, engaging "in-intr-handler"
* event coalescing.
*/
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
0x00000001);
if (tg3_irq_sync(tp))
goto out; goto out;
sblk->status &= ~SD_STATUS_UPDATED;
if (likely(tg3_has_work(tp))) {
prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
netif_rx_schedule(dev); /* schedule NAPI poll */
} else {
/* No work, shared interrupt perhaps? re-enable
* interrupts, and flush that PCI write
*/
tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
0x00000000);
} }
} else { /* shared interrupt */ }
handled = 0;
/*
* Writing any value to intr-mbox-0 clears PCI INTA# and
* chip-internal interrupt pending events.
* Writing non-zero to intr-mbox-0 additional tells the
* NIC to stop sending us irqs, engaging "in-intr-handler"
* event coalescing.
*/
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
if (tg3_irq_sync(tp))
goto out;
sblk->status &= ~SD_STATUS_UPDATED;
if (likely(tg3_has_work(tp))) {
prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
netif_rx_schedule(dev); /* schedule NAPI poll */
} else {
/* No work, shared interrupt perhaps? re-enable
* interrupts, and flush that PCI write
*/
tw32_mailbox_f(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
0x00000000);
} }
out: out:
return IRQ_RETVAL(handled); return IRQ_RETVAL(handled);
...@@ -3611,31 +3613,33 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id) ...@@ -3611,31 +3613,33 @@ static irqreturn_t tg3_interrupt_tagged(int irq, void *dev_id)
* Reading the PCI State register will confirm whether the * Reading the PCI State register will confirm whether the
* interrupt is ours and will flush the status block. * interrupt is ours and will flush the status block.
*/ */
if ((sblk->status_tag != tp->last_tag) || if (unlikely(sblk->status_tag == tp->last_tag)) {
!(tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) { if ((tp->tg3_flags & TG3_FLAG_CHIP_RESETTING) ||
/* (tr32(TG3PCI_PCISTATE) & PCISTATE_INT_NOT_ACTIVE)) {
* writing any value to intr-mbox-0 clears PCI INTA# and handled = 0;
* chip-internal interrupt pending events.
* writing non-zero to intr-mbox-0 additional tells the
* NIC to stop sending us irqs, engaging "in-intr-handler"
* event coalescing.
*/
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
0x00000001);
if (tg3_irq_sync(tp))
goto out; goto out;
if (netif_rx_schedule_prep(dev)) {
prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
/* Update last_tag to mark that this status has been
* seen. Because interrupt may be shared, we may be
* racing with tg3_poll(), so only update last_tag
* if tg3_poll() is not scheduled.
*/
tp->last_tag = sblk->status_tag;
__netif_rx_schedule(dev);
} }
} else { /* shared interrupt */ }
handled = 0;
/*
* writing any value to intr-mbox-0 clears PCI INTA# and
* chip-internal interrupt pending events.
* writing non-zero to intr-mbox-0 additional tells the
* NIC to stop sending us irqs, engaging "in-intr-handler"
* event coalescing.
*/
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000001);
if (tg3_irq_sync(tp))
goto out;
if (netif_rx_schedule_prep(dev)) {
prefetch(&tp->rx_rcb[tp->rx_rcb_ptr]);
/* Update last_tag to mark that this status has been
* seen. Because interrupt may be shared, we may be
* racing with tg3_poll(), so only update last_tag
* if tg3_poll() is not scheduled.
*/
tp->last_tag = sblk->status_tag;
__netif_rx_schedule(dev);
} }
out: out:
return IRQ_RETVAL(handled); return IRQ_RETVAL(handled);
...@@ -4823,6 +4827,19 @@ static int tg3_chip_reset(struct tg3 *tp) ...@@ -4823,6 +4827,19 @@ static int tg3_chip_reset(struct tg3 *tp)
if (write_op == tg3_write_flush_reg32) if (write_op == tg3_write_flush_reg32)
tp->write32 = tg3_write32; tp->write32 = tg3_write32;
/* Prevent the irq handler from reading or writing PCI registers
* during chip reset when the memory enable bit in the PCI command
* register may be cleared. The chip does not generate interrupt
* at this time, but the irq handler may still be called due to irq
* sharing or irqpoll.
*/
tp->tg3_flags |= TG3_FLAG_CHIP_RESETTING;
tp->hw_status->status = 0;
tp->hw_status->status_tag = 0;
tp->last_tag = 0;
smp_mb();
synchronize_irq(tp->pdev->irq);
/* do the reset */ /* do the reset */
val = GRC_MISC_CFG_CORECLK_RESET; val = GRC_MISC_CFG_CORECLK_RESET;
...@@ -4904,6 +4921,8 @@ static int tg3_chip_reset(struct tg3 *tp) ...@@ -4904,6 +4921,8 @@ static int tg3_chip_reset(struct tg3 *tp)
pci_restore_state(tp->pdev); pci_restore_state(tp->pdev);
tp->tg3_flags &= ~TG3_FLAG_CHIP_RESETTING;
/* Make sure PCI-X relaxed ordering bit is clear. */ /* Make sure PCI-X relaxed ordering bit is clear. */
pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val); pci_read_config_dword(tp->pdev, TG3PCI_X_CAPS, &val);
val &= ~PCIX_CAPS_RELAXED_ORDERING; val &= ~PCIX_CAPS_RELAXED_ORDERING;
...@@ -6321,8 +6340,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) ...@@ -6321,8 +6340,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
RDMAC_MODE_ADDROFLOW_ENAB | RDMAC_MODE_FIFOOFLOW_ENAB | RDMAC_MODE_ADDROFLOW_ENAB | RDMAC_MODE_FIFOOFLOW_ENAB |
RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB | RDMAC_MODE_FIFOURUN_ENAB | RDMAC_MODE_FIFOOREAD_ENAB |
RDMAC_MODE_LNGREAD_ENAB); RDMAC_MODE_LNGREAD_ENAB);
if (tp->tg3_flags & TG3_FLAG_SPLIT_MODE)
rdmac_mode |= RDMAC_MODE_SPLIT_ENABLE;
/* If statement applies to 5705 and 5750 PCI devices only */ /* If statement applies to 5705 and 5750 PCI devices only */
if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && if ((GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
...@@ -6495,9 +6512,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy) ...@@ -6495,9 +6512,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
} else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) { } else if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5704) {
val &= ~(PCIX_CAPS_SPLIT_MASK | PCIX_CAPS_BURST_MASK); val &= ~(PCIX_CAPS_SPLIT_MASK | PCIX_CAPS_BURST_MASK);
val |= (PCIX_CAPS_MAX_BURST_CPIOB << PCIX_CAPS_BURST_SHIFT); val |= (PCIX_CAPS_MAX_BURST_CPIOB << 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); tw32(TG3PCI_X_CAPS, val);
} }
...@@ -10863,14 +10877,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp) ...@@ -10863,14 +10877,6 @@ static int __devinit tg3_get_invariants(struct tg3 *tp)
grc_misc_cfg = tr32(GRC_MISC_CFG); grc_misc_cfg = tr32(GRC_MISC_CFG);
grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK; grc_misc_cfg &= GRC_MISC_CFG_BOARD_ID_MASK;
/* Broadcom's driver says that CIOBE multisplit has a bug */
#if 0
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;
}
#endif
if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 && if (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5705 &&
(grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788 || (grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788 ||
grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788M)) grc_misc_cfg == GRC_MISC_CFG_BOARD_ID_5788M))
...@@ -11968,14 +11974,12 @@ static int __devinit tg3_init_one(struct pci_dev *pdev, ...@@ -11968,14 +11974,12 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
i == 5 ? '\n' : ':'); i == 5 ? '\n' : ':');
printk(KERN_INFO "%s: RXcsums[%d] LinkChgREG[%d] " printk(KERN_INFO "%s: RXcsums[%d] LinkChgREG[%d] "
"MIirq[%d] ASF[%d] Split[%d] WireSpeed[%d] " "MIirq[%d] ASF[%d] WireSpeed[%d] TSOcap[%d]\n",
"TSOcap[%d] \n",
dev->name, dev->name,
(tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0, (tp->tg3_flags & TG3_FLAG_RX_CHECKSUMS) != 0,
(tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) != 0, (tp->tg3_flags & TG3_FLAG_USE_LINKCHG_REG) != 0,
(tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) != 0, (tp->tg3_flags & TG3_FLAG_USE_MI_INTERRUPT) != 0,
(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0, (tp->tg3_flags & TG3_FLAG_ENABLE_ASF) != 0,
(tp->tg3_flags & TG3_FLAG_SPLIT_MODE) != 0,
(tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED) == 0, (tp->tg3_flags2 & TG3_FLG2_NO_ETH_WIRE_SPEED) == 0,
(tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) != 0); (tp->tg3_flags2 & TG3_FLG2_TSO_CAPABLE) != 0);
printk(KERN_INFO "%s: dma_rwctrl[%08x] dma_mask[%d-bit]\n", printk(KERN_INFO "%s: dma_rwctrl[%08x] dma_mask[%d-bit]\n",
......
...@@ -2223,7 +2223,7 @@ struct tg3 { ...@@ -2223,7 +2223,7 @@ struct tg3 {
#define TG3_FLAG_40BIT_DMA_BUG 0x08000000 #define TG3_FLAG_40BIT_DMA_BUG 0x08000000
#define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000 #define TG3_FLAG_BROKEN_CHECKSUMS 0x10000000
#define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000 #define TG3_FLAG_GOT_SERDES_FLOWCTL 0x20000000
#define TG3_FLAG_SPLIT_MODE 0x40000000 #define TG3_FLAG_CHIP_RESETTING 0x40000000
#define TG3_FLAG_INIT_COMPLETE 0x80000000 #define TG3_FLAG_INIT_COMPLETE 0x80000000
u32 tg3_flags2; u32 tg3_flags2;
#define TG3_FLG2_RESTART_TIMER 0x00000001 #define TG3_FLG2_RESTART_TIMER 0x00000001
...@@ -2262,9 +2262,6 @@ struct tg3 { ...@@ -2262,9 +2262,6 @@ struct tg3 {
#define TG3_FLG2_NO_FWARE_REPORTED 0x40000000 #define TG3_FLG2_NO_FWARE_REPORTED 0x40000000
#define TG3_FLG2_PHY_ADJUST_TRIM 0x80000000 #define TG3_FLG2_PHY_ADJUST_TRIM 0x80000000
u32 split_mode_max_reqs;
#define SPLIT_MODE_5704_MAX_REQ 3
struct timer_list timer; struct timer_list timer;
u16 timer_counter; u16 timer_counter;
u16 timer_multiplier; u16 timer_multiplier;
......
#ifndef _LMC_MEDIA_H_
#define _LMC_MEDIA_H_
lmc_media_t lmc_ds3_media = {
lmc_ds3_init, /* special media init stuff */
lmc_ds3_default, /* reset to default state */
lmc_ds3_set_status, /* reset status to state provided */
lmc_dummy_set_1, /* set clock source */
lmc_dummy_set2_1, /* set line speed */
lmc_ds3_set_100ft, /* set cable length */
lmc_ds3_set_scram, /* set scrambler */
lmc_ds3_get_link_status, /* get link status */
lmc_dummy_set_1, /* set link status */
lmc_ds3_set_crc_length, /* set CRC length */
lmc_dummy_set_1, /* set T1 or E1 circuit type */
lmc_ds3_watchdog
};
lmc_media_t lmc_hssi_media = {
lmc_hssi_init, /* special media init stuff */
lmc_hssi_default, /* reset to default state */
lmc_hssi_set_status, /* reset status to state provided */
lmc_hssi_set_clock, /* set clock source */
lmc_dummy_set2_1, /* set line speed */
lmc_dummy_set_1, /* set cable length */
lmc_dummy_set_1, /* set scrambler */
lmc_hssi_get_link_status, /* get link status */
lmc_hssi_set_link_status, /* set link status */
lmc_hssi_set_crc_length, /* set CRC length */
lmc_dummy_set_1, /* set T1 or E1 circuit type */
lmc_hssi_watchdog
};
lmc_media_t lmc_ssi_media = { lmc_ssi_init, /* special media init stuff */
lmc_ssi_default, /* reset to default state */
lmc_ssi_set_status, /* reset status to state provided */
lmc_ssi_set_clock, /* set clock source */
lmc_ssi_set_speed, /* set line speed */
lmc_dummy_set_1, /* set cable length */
lmc_dummy_set_1, /* set scrambler */
lmc_ssi_get_link_status, /* get link status */
lmc_ssi_set_link_status, /* set link status */
lmc_ssi_set_crc_length, /* set CRC length */
lmc_dummy_set_1, /* set T1 or E1 circuit type */
lmc_ssi_watchdog
};
lmc_media_t lmc_t1_media = {
lmc_t1_init, /* special media init stuff */
lmc_t1_default, /* reset to default state */
lmc_t1_set_status, /* reset status to state provided */
lmc_t1_set_clock, /* set clock source */
lmc_dummy_set2_1, /* set line speed */
lmc_dummy_set_1, /* set cable length */
lmc_dummy_set_1, /* set scrambler */
lmc_t1_get_link_status, /* get link status */
lmc_dummy_set_1, /* set link status */
lmc_t1_set_crc_length, /* set CRC length */
lmc_t1_set_circuit_type, /* set T1 or E1 circuit type */
lmc_t1_watchdog
};
#endif
...@@ -34,6 +34,7 @@ struct fib_rules_ops ...@@ -34,6 +34,7 @@ struct fib_rules_ops
int family; int family;
struct list_head list; struct list_head list;
int rule_size; int rule_size;
int addr_size;
int (*action)(struct fib_rule *, int (*action)(struct fib_rule *,
struct flowi *, int, struct flowi *, int,
......
...@@ -58,6 +58,7 @@ struct fib6_node ...@@ -58,6 +58,7 @@ struct fib6_node
__u16 fn_bit; /* bit key */ __u16 fn_bit; /* bit key */
__u16 fn_flags; __u16 fn_flags;
__u32 fn_sernum; __u32 fn_sernum;
struct rt6_info *rr_ptr;
}; };
#ifndef CONFIG_IPV6_SUBTREES #ifndef CONFIG_IPV6_SUBTREES
......
...@@ -36,7 +36,7 @@ struct neigh_parms ...@@ -36,7 +36,7 @@ struct neigh_parms
struct net_device *dev; struct net_device *dev;
struct neigh_parms *next; struct neigh_parms *next;
int (*neigh_setup)(struct neighbour *); int (*neigh_setup)(struct neighbour *);
void (*neigh_destructor)(struct neighbour *); void (*neigh_cleanup)(struct neighbour *);
struct neigh_table *tbl; struct neigh_table *tbl;
void *sysctl_table; void *sysctl_table;
......
...@@ -261,14 +261,6 @@ static void clip_pop(struct atm_vcc *vcc, struct sk_buff *skb) ...@@ -261,14 +261,6 @@ static void clip_pop(struct atm_vcc *vcc, struct sk_buff *skb)
spin_unlock_irqrestore(&PRIV(dev)->xoff_lock, flags); spin_unlock_irqrestore(&PRIV(dev)->xoff_lock, flags);
} }
static void clip_neigh_destroy(struct neighbour *neigh)
{
DPRINTK("clip_neigh_destroy (neigh %p)\n", neigh);
if (NEIGH2ENTRY(neigh)->vccs)
printk(KERN_CRIT "clip_neigh_destroy: vccs != NULL !!!\n");
NEIGH2ENTRY(neigh)->vccs = (void *) NEIGHBOR_DEAD;
}
static void clip_neigh_solicit(struct neighbour *neigh, struct sk_buff *skb) static void clip_neigh_solicit(struct neighbour *neigh, struct sk_buff *skb)
{ {
DPRINTK("clip_neigh_solicit (neigh %p, skb %p)\n", neigh, skb); DPRINTK("clip_neigh_solicit (neigh %p, skb %p)\n", neigh, skb);
...@@ -342,7 +334,6 @@ static struct neigh_table clip_tbl = { ...@@ -342,7 +334,6 @@ static struct neigh_table clip_tbl = {
/* parameters are copied from ARP ... */ /* parameters are copied from ARP ... */
.parms = { .parms = {
.tbl = &clip_tbl, .tbl = &clip_tbl,
.neigh_destructor = clip_neigh_destroy,
.base_reachable_time = 30 * HZ, .base_reachable_time = 30 * HZ,
.retrans_time = 1 * HZ, .retrans_time = 1 * HZ,
.gc_staletime = 60 * HZ, .gc_staletime = 60 * HZ,
......
# #
# Amateur Radio protocols and AX.25 device configuration # Amateur Radio protocols and AX.25 device configuration
# #
# 19971130 Now in an own category to make correct compilation of the
# AX.25 stuff easier...
# Joerg Reuter DL1BKE <jreuter@yaina.de>
# 19980129 Moved to net/ax25/Config.in, sourcing device drivers.
menuconfig HAMRADIO menuconfig HAMRADIO
depends on NET depends on NET
bool "Amateur Radio support" bool "Amateur Radio support"
help help
If you want to connect your Linux box to an amateur radio, answer Y If you want to connect your Linux box to an amateur radio, answer Y
here. You want to read <http://www.tapr.org/tapr/html/pkthome.html> and here. You want to read <http://www.tapr.org/tapr/html/pkthome.html>
the AX25-HOWTO, available from <http://www.tldp.org/docs.html#howto>. and more specifically about AX.25 on Linux
<http://www.linux-ax25.org/>.
Note that the answer to this question won't directly affect the Note that the answer to this question won't directly affect the
kernel: saying N will just cause the configurator to skip all kernel: saying N will just cause the configurator to skip all
the questions about amateur radio. the questions about amateur radio.
comment "Packet Radio protocols" comment "Packet Radio protocols"
depends on HAMRADIO && NET depends on HAMRADIO
config AX25 config AX25
tristate "Amateur Radio AX.25 Level 2 protocol" tristate "Amateur Radio AX.25 Level 2 protocol"
depends on HAMRADIO && NET depends on HAMRADIO
---help--- help
This is the protocol used for computer communication over amateur This is the protocol used for computer communication over amateur
radio. It is either used by itself for point-to-point links, or to radio. It is either used by itself for point-to-point links, or to
carry other protocols such as tcp/ip. To use it, you need a device carry other protocols such as tcp/ip. To use it, you need a device
...@@ -52,6 +49,7 @@ config AX25 ...@@ -52,6 +49,7 @@ config AX25
config AX25_DAMA_SLAVE config AX25_DAMA_SLAVE
bool "AX.25 DAMA Slave support" bool "AX.25 DAMA Slave support"
default y
depends on AX25 depends on AX25
help help
DAMA is a mechanism to prevent collisions when doing AX.25 DAMA is a mechanism to prevent collisions when doing AX.25
...@@ -59,23 +57,38 @@ config AX25_DAMA_SLAVE ...@@ -59,23 +57,38 @@ config AX25_DAMA_SLAVE
from clients (called "slaves") and redistributes it to other slaves. from clients (called "slaves") and redistributes it to other slaves.
If you say Y here, your Linux box will act as a DAMA slave; this is If you say Y here, your Linux box will act as a DAMA slave; this is
transparent in that you don't have to do any special DAMA transparent in that you don't have to do any special DAMA
configuration. (Linux cannot yet act as a DAMA server.) If unsure, configuration. Linux cannot yet act as a DAMA server. This option
say N. only compiles DAMA slave support into the kernel. It still needs to
be enabled at runtime. For more about DAMA see
<http://www.linux-ax25.org>. If unsure, say Y.
# placeholder until implemented
config AX25_DAMA_MASTER
bool 'AX.25 DAMA Master support'
depends on AX25_DAMA_SLAVE && BROKEN
help
DAMA is a mechanism to prevent collisions when doing AX.25
networking. A DAMA server (called "master") accepts incoming traffic
from clients (called "slaves") and redistributes it to other slaves.
If you say Y here, your Linux box will act as a DAMA master; this is
transparent in that you don't have to do any special DAMA
configuration. Linux cannot yet act as a DAMA server. This option
only compiles DAMA slave support into the kernel. It still needs to
be explicitly enabled, so if unsure, say Y.
# bool ' AX.25 DAMA Master support' CONFIG_AX25_DAMA_MASTER
config NETROM config NETROM
tristate "Amateur Radio NET/ROM protocol" tristate "Amateur Radio NET/ROM protocol"
depends on AX25 depends on AX25
---help--- help
NET/ROM is a network layer protocol on top of AX.25 useful for NET/ROM is a network layer protocol on top of AX.25 useful for
routing. routing.
A comprehensive listing of all the software for Linux amateur radio A comprehensive listing of all the software for Linux amateur radio
users as well as information about how to configure an AX.25 port is users as well as information about how to configure an AX.25 port is
contained in the AX25-HOWTO, available from contained in the Linux Ham Wiki, available from
<http://www.tldp.org/docs.html#howto>. You also might want to <http://www.linux-ax25.org>. You also might want to check out the
check out the file <file:Documentation/networking/ax25.txt>. More file <file:Documentation/networking/ax25.txt>. More information about
information about digital amateur radio in general is on the WWW at digital amateur radio in general is on the WWW at
<http://www.tapr.org/tapr/html/pkthome.html>. <http://www.tapr.org/tapr/html/pkthome.html>.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
...@@ -84,27 +97,25 @@ config NETROM ...@@ -84,27 +97,25 @@ config NETROM
config ROSE config ROSE
tristate "Amateur Radio X.25 PLP (Rose)" tristate "Amateur Radio X.25 PLP (Rose)"
depends on AX25 depends on AX25
---help--- help
The Packet Layer Protocol (PLP) is a way to route packets over X.25 The Packet Layer Protocol (PLP) is a way to route packets over X.25
connections in general and amateur radio AX.25 connections in connections in general and amateur radio AX.25 connections in
particular, essentially an alternative to NET/ROM. particular, essentially an alternative to NET/ROM.
A comprehensive listing of all the software for Linux amateur radio A comprehensive listing of all the software for Linux amateur radio
users as well as information about how to configure an AX.25 port is users as well as information about how to configure an AX.25 port is
contained in the AX25-HOWTO, available from contained in the Linux Ham Wiki, available from
<http://www.tldp.org/docs.html#howto>. You also might want to <http://www.linux-ax25.org>. You also might want to check out the
check out the file <file:Documentation/networking/ax25.txt>. More file <file:Documentation/networking/ax25.txt>. More information about
information about digital amateur radio in general is on the WWW at digital amateur radio in general is on the WWW at
<http://www.tapr.org/tapr/html/pkthome.html>. <http://www.tapr.org/tapr/html/pkthome.html>.
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called rose. module will be called rose.
menu "AX.25 network device drivers" menu "AX.25 network device drivers"
depends on HAMRADIO && NET && AX25!=n depends on HAMRADIO && AX25
source "drivers/net/hamradio/Kconfig" source "drivers/net/hamradio/Kconfig"
endmenu endmenu
...@@ -1750,10 +1750,10 @@ static int ing_filter(struct sk_buff *skb) ...@@ -1750,10 +1750,10 @@ static int ing_filter(struct sk_buff *skb)
skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_INGRESS); skb->tc_verd = SET_TC_AT(skb->tc_verd,AT_INGRESS);
spin_lock(&dev->ingress_lock); spin_lock(&dev->queue_lock);
if ((q = dev->qdisc_ingress) != NULL) if ((q = dev->qdisc_ingress) != NULL)
result = q->enqueue(skb, q); result = q->enqueue(skb, q);
spin_unlock(&dev->ingress_lock); spin_unlock(&dev->queue_lock);
} }
......
...@@ -152,6 +152,28 @@ int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl, ...@@ -152,6 +152,28 @@ int fib_rules_lookup(struct fib_rules_ops *ops, struct flowi *fl,
EXPORT_SYMBOL_GPL(fib_rules_lookup); EXPORT_SYMBOL_GPL(fib_rules_lookup);
static int validate_rulemsg(struct fib_rule_hdr *frh, struct nlattr **tb,
struct fib_rules_ops *ops)
{
int err = -EINVAL;
if (frh->src_len)
if (tb[FRA_SRC] == NULL ||
frh->src_len > (ops->addr_size * 8) ||
nla_len(tb[FRA_SRC]) != ops->addr_size)
goto errout;
if (frh->dst_len)
if (tb[FRA_DST] == NULL ||
frh->dst_len > (ops->addr_size * 8) ||
nla_len(tb[FRA_DST]) != ops->addr_size)
goto errout;
err = 0;
errout:
return err;
}
int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
{ {
struct fib_rule_hdr *frh = nlmsg_data(nlh); struct fib_rule_hdr *frh = nlmsg_data(nlh);
...@@ -173,6 +195,10 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) ...@@ -173,6 +195,10 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
if (err < 0) if (err < 0)
goto errout; goto errout;
err = validate_rulemsg(frh, tb, ops);
if (err < 0)
goto errout;
rule = kzalloc(ops->rule_size, GFP_KERNEL); rule = kzalloc(ops->rule_size, GFP_KERNEL);
if (rule == NULL) { if (rule == NULL) {
err = -ENOMEM; err = -ENOMEM;
...@@ -260,6 +286,10 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) ...@@ -260,6 +286,10 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
if (err < 0) if (err < 0)
goto errout; goto errout;
err = validate_rulemsg(frh, tb, ops);
if (err < 0)
goto errout;
list_for_each_entry(rule, ops->rules_list, list) { list_for_each_entry(rule, ops->rules_list, list) {
if (frh->action && (frh->action != rule->action)) if (frh->action && (frh->action != rule->action))
continue; continue;
......
...@@ -140,6 +140,8 @@ static int neigh_forced_gc(struct neigh_table *tbl) ...@@ -140,6 +140,8 @@ static int neigh_forced_gc(struct neigh_table *tbl)
n->dead = 1; n->dead = 1;
shrunk = 1; shrunk = 1;
write_unlock(&n->lock); write_unlock(&n->lock);
if (n->parms->neigh_cleanup)
n->parms->neigh_cleanup(n);
neigh_release(n); neigh_release(n);
continue; continue;
} }
...@@ -211,6 +213,8 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev) ...@@ -211,6 +213,8 @@ static void neigh_flush_dev(struct neigh_table *tbl, struct net_device *dev)
NEIGH_PRINTK2("neigh %p is stray.\n", n); NEIGH_PRINTK2("neigh %p is stray.\n", n);
} }
write_unlock(&n->lock); write_unlock(&n->lock);
if (n->parms->neigh_cleanup)
n->parms->neigh_cleanup(n);
neigh_release(n); neigh_release(n);
} }
} }
...@@ -582,9 +586,6 @@ void neigh_destroy(struct neighbour *neigh) ...@@ -582,9 +586,6 @@ void neigh_destroy(struct neighbour *neigh)
kfree(hh); kfree(hh);
} }
if (neigh->parms->neigh_destructor)
(neigh->parms->neigh_destructor)(neigh);
skb_queue_purge(&neigh->arp_queue); skb_queue_purge(&neigh->arp_queue);
dev_put(neigh->dev); dev_put(neigh->dev);
...@@ -675,6 +676,8 @@ static void neigh_periodic_timer(unsigned long arg) ...@@ -675,6 +676,8 @@ static void neigh_periodic_timer(unsigned long arg)
*np = n->next; *np = n->next;
n->dead = 1; n->dead = 1;
write_unlock(&n->lock); write_unlock(&n->lock);
if (n->parms->neigh_cleanup)
n->parms->neigh_cleanup(n);
neigh_release(n); neigh_release(n);
continue; continue;
} }
...@@ -2088,8 +2091,11 @@ void __neigh_for_each_release(struct neigh_table *tbl, ...@@ -2088,8 +2091,11 @@ void __neigh_for_each_release(struct neigh_table *tbl,
} else } else
np = &n->next; np = &n->next;
write_unlock(&n->lock); write_unlock(&n->lock);
if (release) if (release) {
if (n->parms->neigh_cleanup)
n->parms->neigh_cleanup(n);
neigh_release(n); neigh_release(n);
}
} }
} }
} }
......
...@@ -191,7 +191,6 @@ extern void dccp_send_sync(struct sock *sk, const u64 seq, ...@@ -191,7 +191,6 @@ extern void dccp_send_sync(struct sock *sk, const u64 seq,
const enum dccp_pkt_type pkt_type); const enum dccp_pkt_type pkt_type);
extern void dccp_write_xmit(struct sock *sk, int block); extern void dccp_write_xmit(struct sock *sk, int block);
extern void dccp_write_xmit_timer(unsigned long data);
extern void dccp_write_space(struct sock *sk); extern void dccp_write_space(struct sock *sk);
extern void dccp_init_xmit_timers(struct sock *sk); extern void dccp_init_xmit_timers(struct sock *sk);
......
...@@ -262,7 +262,7 @@ static void dccp_delack_timer(unsigned long data) ...@@ -262,7 +262,7 @@ static void dccp_delack_timer(unsigned long data)
} }
/* Transmit-delay timer: used by the CCIDs to delay actual send time */ /* Transmit-delay timer: used by the CCIDs to delay actual send time */
void dccp_write_xmit_timer(unsigned long data) static void dccp_write_xmit_timer(unsigned long data)
{ {
struct sock *sk = (struct sock *)data; struct sock *sk = (struct sock *)data;
struct dccp_sock *dp = dccp_sk(sk); struct dccp_sock *dp = dccp_sk(sk);
......
...@@ -63,7 +63,7 @@ static struct ...@@ -63,7 +63,7 @@ static struct
{ {
int error; int error;
u8 scope; u8 scope;
} dn_fib_props[RTA_MAX+1] = { } dn_fib_props[RTN_MAX+1] = {
[RTN_UNSPEC] = { .error = 0, .scope = RT_SCOPE_NOWHERE }, [RTN_UNSPEC] = { .error = 0, .scope = RT_SCOPE_NOWHERE },
[RTN_UNICAST] = { .error = 0, .scope = RT_SCOPE_UNIVERSE }, [RTN_UNICAST] = { .error = 0, .scope = RT_SCOPE_UNIVERSE },
[RTN_LOCAL] = { .error = 0, .scope = RT_SCOPE_HOST }, [RTN_LOCAL] = { .error = 0, .scope = RT_SCOPE_HOST },
...@@ -276,6 +276,9 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta ...@@ -276,6 +276,9 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta
struct dn_fib_info *ofi; struct dn_fib_info *ofi;
int nhs = 1; int nhs = 1;
if (r->rtm_type > RTN_MAX)
goto err_inval;
if (dn_fib_props[r->rtm_type].scope > r->rtm_scope) if (dn_fib_props[r->rtm_type].scope > r->rtm_scope)
goto err_inval; goto err_inval;
......
...@@ -109,8 +109,6 @@ static int dn_fib_rule_action(struct fib_rule *rule, struct flowi *flp, ...@@ -109,8 +109,6 @@ static int dn_fib_rule_action(struct fib_rule *rule, struct flowi *flp,
static struct nla_policy dn_fib_rule_policy[FRA_MAX+1] __read_mostly = { static struct nla_policy dn_fib_rule_policy[FRA_MAX+1] __read_mostly = {
FRA_GENERIC_POLICY, FRA_GENERIC_POLICY,
[FRA_SRC] = { .type = NLA_U16 },
[FRA_DST] = { .type = NLA_U16 },
}; };
static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
...@@ -133,7 +131,7 @@ static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb, ...@@ -133,7 +131,7 @@ static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
int err = -EINVAL; int err = -EINVAL;
struct dn_fib_rule *r = (struct dn_fib_rule *)rule; struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
if (frh->src_len > 16 || frh->dst_len > 16 || frh->tos) if (frh->tos)
goto errout; goto errout;
if (rule->table == RT_TABLE_UNSPEC) { if (rule->table == RT_TABLE_UNSPEC) {
...@@ -150,10 +148,10 @@ static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb, ...@@ -150,10 +148,10 @@ static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
} }
} }
if (tb[FRA_SRC]) if (frh->src_len)
r->src = nla_get_le16(tb[FRA_SRC]); r->src = nla_get_le16(tb[FRA_SRC]);
if (tb[FRA_DST]) if (frh->dst_len)
r->dst = nla_get_le16(tb[FRA_DST]); r->dst = nla_get_le16(tb[FRA_DST]);
r->src_len = frh->src_len; r->src_len = frh->src_len;
...@@ -176,10 +174,10 @@ static int dn_fib_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, ...@@ -176,10 +174,10 @@ static int dn_fib_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
if (frh->dst_len && (r->dst_len != frh->dst_len)) if (frh->dst_len && (r->dst_len != frh->dst_len))
return 0; return 0;
if (tb[FRA_SRC] && (r->src != nla_get_le16(tb[FRA_SRC]))) if (frh->src_len && (r->src != nla_get_le16(tb[FRA_SRC])))
return 0; return 0;
if (tb[FRA_DST] && (r->dst != nla_get_le16(tb[FRA_DST]))) if (frh->dst_len && (r->dst != nla_get_le16(tb[FRA_DST])))
return 0; return 0;
return 1; return 1;
...@@ -249,6 +247,7 @@ int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) ...@@ -249,6 +247,7 @@ int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
static struct fib_rules_ops dn_fib_rules_ops = { static struct fib_rules_ops dn_fib_rules_ops = {
.family = AF_DECnet, .family = AF_DECnet,
.rule_size = sizeof(struct dn_fib_rule), .rule_size = sizeof(struct dn_fib_rule),
.addr_size = sizeof(u16),
.action = dn_fib_rule_action, .action = dn_fib_rule_action,
.match = dn_fib_rule_match, .match = dn_fib_rule_match,
.configure = dn_fib_rule_configure, .configure = dn_fib_rule_configure,
......
...@@ -493,6 +493,11 @@ static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh, ...@@ -493,6 +493,11 @@ static int rtm_to_fib_config(struct sk_buff *skb, struct nlmsghdr *nlh,
cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid; cfg->fc_nlinfo.pid = NETLINK_CB(skb).pid;
cfg->fc_nlinfo.nlh = nlh; cfg->fc_nlinfo.nlh = nlh;
if (cfg->fc_type > RTN_MAX) {
err = -EINVAL;
goto errout;
}
nlmsg_for_each_attr(attr, nlh, sizeof(struct rtmsg), remaining) { nlmsg_for_each_attr(attr, nlh, sizeof(struct rtmsg), remaining) {
switch (attr->nla_type) { switch (attr->nla_type) {
case RTA_DST: case RTA_DST:
......
...@@ -171,8 +171,6 @@ static struct fib_table *fib_empty_table(void) ...@@ -171,8 +171,6 @@ static struct fib_table *fib_empty_table(void)
static struct nla_policy fib4_rule_policy[FRA_MAX+1] __read_mostly = { static struct nla_policy fib4_rule_policy[FRA_MAX+1] __read_mostly = {
FRA_GENERIC_POLICY, FRA_GENERIC_POLICY,
[FRA_SRC] = { .type = NLA_U32 },
[FRA_DST] = { .type = NLA_U32 },
[FRA_FLOW] = { .type = NLA_U32 }, [FRA_FLOW] = { .type = NLA_U32 },
}; };
...@@ -183,8 +181,7 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, ...@@ -183,8 +181,7 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
int err = -EINVAL; int err = -EINVAL;
struct fib4_rule *rule4 = (struct fib4_rule *) rule; struct fib4_rule *rule4 = (struct fib4_rule *) rule;
if (frh->src_len > 32 || frh->dst_len > 32 || if (frh->tos & ~IPTOS_TOS_MASK)
(frh->tos & ~IPTOS_TOS_MASK))
goto errout; goto errout;
if (rule->table == RT_TABLE_UNSPEC) { if (rule->table == RT_TABLE_UNSPEC) {
...@@ -201,10 +198,10 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb, ...@@ -201,10 +198,10 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
} }
} }
if (tb[FRA_SRC]) if (frh->src_len)
rule4->src = nla_get_be32(tb[FRA_SRC]); rule4->src = nla_get_be32(tb[FRA_SRC]);
if (tb[FRA_DST]) if (frh->dst_len)
rule4->dst = nla_get_be32(tb[FRA_DST]); rule4->dst = nla_get_be32(tb[FRA_DST]);
#ifdef CONFIG_NET_CLS_ROUTE #ifdef CONFIG_NET_CLS_ROUTE
...@@ -242,10 +239,10 @@ static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, ...@@ -242,10 +239,10 @@ static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
return 0; return 0;
#endif #endif
if (tb[FRA_SRC] && (rule4->src != nla_get_be32(tb[FRA_SRC]))) if (frh->src_len && (rule4->src != nla_get_be32(tb[FRA_SRC])))
return 0; return 0;
if (tb[FRA_DST] && (rule4->dst != nla_get_be32(tb[FRA_DST]))) if (frh->dst_len && (rule4->dst != nla_get_be32(tb[FRA_DST])))
return 0; return 0;
return 1; return 1;
...@@ -309,6 +306,7 @@ static size_t fib4_rule_nlmsg_payload(struct fib_rule *rule) ...@@ -309,6 +306,7 @@ static size_t fib4_rule_nlmsg_payload(struct fib_rule *rule)
static struct fib_rules_ops fib4_rules_ops = { static struct fib_rules_ops fib4_rules_ops = {
.family = AF_INET, .family = AF_INET,
.rule_size = sizeof(struct fib4_rule), .rule_size = sizeof(struct fib4_rule),
.addr_size = sizeof(u32),
.action = fib4_rule_action, .action = fib4_rule_action,
.match = fib4_rule_match, .match = fib4_rule_match,
.configure = fib4_rule_configure, .configure = fib4_rule_configure,
......
...@@ -89,7 +89,7 @@ static const struct ...@@ -89,7 +89,7 @@ static const struct
{ {
int error; int error;
u8 scope; u8 scope;
} fib_props[RTA_MAX + 1] = { } fib_props[RTN_MAX + 1] = {
{ {
.error = 0, .error = 0,
.scope = RT_SCOPE_NOWHERE, .scope = RT_SCOPE_NOWHERE,
......
...@@ -1123,6 +1123,9 @@ fib_insert_node(struct trie *t, int *err, u32 key, int plen) ...@@ -1123,6 +1123,9 @@ fib_insert_node(struct trie *t, int *err, u32 key, int plen)
return fa_head; return fa_head;
} }
/*
* Caller must hold RTNL.
*/
static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg) static int fn_trie_insert(struct fib_table *tb, struct fib_config *cfg)
{ {
struct trie *t = (struct trie *) tb->tb_data; struct trie *t = (struct trie *) tb->tb_data;
...@@ -1540,6 +1543,9 @@ static int trie_leaf_remove(struct trie *t, t_key key) ...@@ -1540,6 +1543,9 @@ static int trie_leaf_remove(struct trie *t, t_key key)
return 1; return 1;
} }
/*
* Caller must hold RTNL.
*/
static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg) static int fn_trie_delete(struct fib_table *tb, struct fib_config *cfg)
{ {
struct trie *t = (struct trie *) tb->tb_data; struct trie *t = (struct trie *) tb->tb_data;
...@@ -1718,6 +1724,9 @@ static struct leaf *nextleaf(struct trie *t, struct leaf *thisleaf) ...@@ -1718,6 +1724,9 @@ static struct leaf *nextleaf(struct trie *t, struct leaf *thisleaf)
return NULL; /* Ready. Root of trie */ return NULL; /* Ready. Root of trie */
} }
/*
* Caller must hold RTNL.
*/
static int fn_trie_flush(struct fib_table *tb) static int fn_trie_flush(struct fib_table *tb)
{ {
struct trie *t = (struct trie *) tb->tb_data; struct trie *t = (struct trie *) tb->tb_data;
......
...@@ -131,8 +131,6 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) ...@@ -131,8 +131,6 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
static struct nla_policy fib6_rule_policy[FRA_MAX+1] __read_mostly = { static struct nla_policy fib6_rule_policy[FRA_MAX+1] __read_mostly = {
FRA_GENERIC_POLICY, FRA_GENERIC_POLICY,
[FRA_SRC] = { .len = sizeof(struct in6_addr) },
[FRA_DST] = { .len = sizeof(struct in6_addr) },
}; };
static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
...@@ -142,9 +140,6 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, ...@@ -142,9 +140,6 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
int err = -EINVAL; int err = -EINVAL;
struct fib6_rule *rule6 = (struct fib6_rule *) rule; struct fib6_rule *rule6 = (struct fib6_rule *) rule;
if (frh->src_len > 128 || frh->dst_len > 128)
goto errout;
if (rule->action == FR_ACT_TO_TBL) { if (rule->action == FR_ACT_TO_TBL) {
if (rule->table == RT6_TABLE_UNSPEC) if (rule->table == RT6_TABLE_UNSPEC)
goto errout; goto errout;
...@@ -155,11 +150,11 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, ...@@ -155,11 +150,11 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
} }
} }
if (tb[FRA_SRC]) if (frh->src_len)
nla_memcpy(&rule6->src.addr, tb[FRA_SRC], nla_memcpy(&rule6->src.addr, tb[FRA_SRC],
sizeof(struct in6_addr)); sizeof(struct in6_addr));
if (tb[FRA_DST]) if (frh->dst_len)
nla_memcpy(&rule6->dst.addr, tb[FRA_DST], nla_memcpy(&rule6->dst.addr, tb[FRA_DST],
sizeof(struct in6_addr)); sizeof(struct in6_addr));
...@@ -186,11 +181,11 @@ static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh, ...@@ -186,11 +181,11 @@ static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
if (frh->tos && (rule6->tclass != frh->tos)) if (frh->tos && (rule6->tclass != frh->tos))
return 0; return 0;
if (tb[FRA_SRC] && if (frh->src_len &&
nla_memcmp(tb[FRA_SRC], &rule6->src.addr, sizeof(struct in6_addr))) nla_memcmp(tb[FRA_SRC], &rule6->src.addr, sizeof(struct in6_addr)))
return 0; return 0;
if (tb[FRA_DST] && if (frh->dst_len &&
nla_memcmp(tb[FRA_DST], &rule6->dst.addr, sizeof(struct in6_addr))) nla_memcmp(tb[FRA_DST], &rule6->dst.addr, sizeof(struct in6_addr)))
return 0; return 0;
...@@ -240,6 +235,7 @@ static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule) ...@@ -240,6 +235,7 @@ static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule)
static struct fib_rules_ops fib6_rules_ops = { static struct fib_rules_ops fib6_rules_ops = {
.family = AF_INET6, .family = AF_INET6,
.rule_size = sizeof(struct fib6_rule), .rule_size = sizeof(struct fib6_rule),
.addr_size = sizeof(struct in6_addr),
.action = fib6_rule_action, .action = fib6_rule_action,
.match = fib6_rule_match, .match = fib6_rule_match,
.configure = fib6_rule_configure, .configure = fib6_rule_configure,
......
...@@ -658,6 +658,10 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt, ...@@ -658,6 +658,10 @@ static int fib6_add_rt2node(struct fib6_node *fn, struct rt6_info *rt,
ins = &iter->u.dst.rt6_next; ins = &iter->u.dst.rt6_next;
} }
/* Reset round-robin state, if necessary */
if (ins == &fn->leaf)
fn->rr_ptr = NULL;
/* /*
* insert node * insert node
*/ */
...@@ -1109,6 +1113,10 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp, ...@@ -1109,6 +1113,10 @@ static void fib6_del_route(struct fib6_node *fn, struct rt6_info **rtp,
rt6_stats.fib_rt_entries--; rt6_stats.fib_rt_entries--;
rt6_stats.fib_discarded_routes++; rt6_stats.fib_discarded_routes++;
/* Reset round-robin state, if necessary */
if (fn->rr_ptr == rt)
fn->rr_ptr = NULL;
/* Adjust walkers */ /* Adjust walkers */
read_lock(&fib6_walker_lock); read_lock(&fib6_walker_lock);
FOR_WALKERS(w) { FOR_WALKERS(w) {
......
...@@ -363,55 +363,76 @@ static int rt6_score_route(struct rt6_info *rt, int oif, ...@@ -363,55 +363,76 @@ static int rt6_score_route(struct rt6_info *rt, int oif,
return m; return m;
} }
static struct rt6_info *rt6_select(struct rt6_info **head, int oif, static struct rt6_info *find_match(struct rt6_info *rt, int oif, int strict,
int strict) int *mpri, struct rt6_info *match)
{ {
struct rt6_info *match = NULL, *last = NULL; int m;
struct rt6_info *rt, *rt0 = *head;
u32 metric; if (rt6_check_expired(rt))
goto out;
m = rt6_score_route(rt, oif, strict);
if (m < 0)
goto out;
if (m > *mpri) {
if (strict & RT6_LOOKUP_F_REACHABLE)
rt6_probe(match);
*mpri = m;
match = rt;
} else if (strict & RT6_LOOKUP_F_REACHABLE) {
rt6_probe(rt);
}
out:
return match;
}
static struct rt6_info *find_rr_leaf(struct fib6_node *fn,
struct rt6_info *rr_head,
u32 metric, int oif, int strict)
{
struct rt6_info *rt, *match;
int mpri = -1; int mpri = -1;
RT6_TRACE("%s(head=%p(*head=%p), oif=%d)\n", match = NULL;
__FUNCTION__, head, head ? *head : NULL, oif); for (rt = rr_head; rt && rt->rt6i_metric == metric;
rt = rt->u.dst.rt6_next)
match = find_match(rt, oif, strict, &mpri, match);
for (rt = fn->leaf; rt && rt != rr_head && rt->rt6i_metric == metric;
rt = rt->u.dst.rt6_next)
match = find_match(rt, oif, strict, &mpri, match);
for (rt = rt0, metric = rt0->rt6i_metric; return match;
rt && rt->rt6i_metric == metric && (!last || rt != rt0); }
rt = rt->u.dst.rt6_next) {
int m;
if (rt6_check_expired(rt)) static struct rt6_info *rt6_select(struct fib6_node *fn, int oif, int strict)
continue; {
struct rt6_info *match, *rt0;
last = rt; RT6_TRACE("%s(fn->leaf=%p, oif=%d)\n",
__FUNCTION__, fn->leaf, oif);
m = rt6_score_route(rt, oif, strict); rt0 = fn->rr_ptr;
if (m < 0) if (!rt0)
continue; fn->rr_ptr = rt0 = fn->leaf;
if (m > mpri) { match = find_rr_leaf(fn, rt0, rt0->rt6i_metric, oif, strict);
if (strict & RT6_LOOKUP_F_REACHABLE)
rt6_probe(match);
match = rt;
mpri = m;
} else if (strict & RT6_LOOKUP_F_REACHABLE) {
rt6_probe(rt);
}
}
if (!match && if (!match &&
(strict & RT6_LOOKUP_F_REACHABLE) && (strict & RT6_LOOKUP_F_REACHABLE)) {
last && last != rt0) { struct rt6_info *next = rt0->u.dst.rt6_next;
/* no entries matched; do round-robin */ /* no entries matched; do round-robin */
static DEFINE_SPINLOCK(lock); if (!next || next->rt6i_metric != rt0->rt6i_metric)
spin_lock(&lock); next = fn->leaf;
*head = rt0->u.dst.rt6_next;
rt0->u.dst.rt6_next = last->u.dst.rt6_next; if (next != rt0)
last->u.dst.rt6_next = rt0; fn->rr_ptr = next;
spin_unlock(&lock);
} }
RT6_TRACE("%s() => %p, score=%d\n", RT6_TRACE("%s() => %p\n",
__FUNCTION__, match, mpri); __FUNCTION__, match);
return (match ? match : &ip6_null_entry); return (match ? match : &ip6_null_entry);
} }
...@@ -657,7 +678,7 @@ static struct rt6_info *ip6_pol_route_input(struct fib6_table *table, ...@@ -657,7 +678,7 @@ static struct rt6_info *ip6_pol_route_input(struct fib6_table *table,
fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
restart: restart:
rt = rt6_select(&fn->leaf, fl->iif, strict | reachable); rt = rt6_select(fn, fl->iif, strict | reachable);
BACKTRACK(&fl->fl6_src); BACKTRACK(&fl->fl6_src);
if (rt == &ip6_null_entry || if (rt == &ip6_null_entry ||
rt->rt6i_flags & RTF_CACHE) rt->rt6i_flags & RTF_CACHE)
...@@ -752,7 +773,7 @@ static struct rt6_info *ip6_pol_route_output(struct fib6_table *table, ...@@ -752,7 +773,7 @@ static struct rt6_info *ip6_pol_route_output(struct fib6_table *table,
fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src); fn = fib6_lookup(&table->tb6_root, &fl->fl6_dst, &fl->fl6_src);
restart: restart:
rt = rt6_select(&fn->leaf, fl->oif, strict | reachable); rt = rt6_select(fn, fl->oif, strict | reachable);
BACKTRACK(&fl->fl6_src); BACKTRACK(&fl->fl6_src);
if (rt == &ip6_null_entry || if (rt == &ip6_null_entry ||
rt->rt6i_flags & RTF_CACHE) rt->rt6i_flags & RTF_CACHE)
......
...@@ -81,6 +81,13 @@ static void basic_put(struct tcf_proto *tp, unsigned long f) ...@@ -81,6 +81,13 @@ static void basic_put(struct tcf_proto *tp, unsigned long f)
static int basic_init(struct tcf_proto *tp) static int basic_init(struct tcf_proto *tp)
{ {
struct basic_head *head;
head = kzalloc(sizeof(*head), GFP_KERNEL);
if (head == NULL)
return -ENOBUFS;
INIT_LIST_HEAD(&head->flist);
tp->root = head;
return 0; return 0;
} }
...@@ -176,15 +183,6 @@ static int basic_change(struct tcf_proto *tp, unsigned long base, u32 handle, ...@@ -176,15 +183,6 @@ static int basic_change(struct tcf_proto *tp, unsigned long base, u32 handle,
} }
err = -ENOBUFS; err = -ENOBUFS;
if (head == NULL) {
head = kzalloc(sizeof(*head), GFP_KERNEL);
if (head == NULL)
goto errout;
INIT_LIST_HEAD(&head->flist);
tp->root = head;
}
f = kzalloc(sizeof(*f), GFP_KERNEL); f = kzalloc(sizeof(*f), GFP_KERNEL);
if (f == NULL) if (f == NULL)
goto errout; goto errout;
......
...@@ -1381,7 +1381,7 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, ...@@ -1381,7 +1381,7 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr,
err = sock_attach_fd(newsock, newfile); err = sock_attach_fd(newsock, newfile);
if (err < 0) if (err < 0)
goto out_fd; goto out_fd_simple;
err = security_socket_accept(sock, newsock); err = security_socket_accept(sock, newsock);
if (err) if (err)
...@@ -1414,6 +1414,11 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr, ...@@ -1414,6 +1414,11 @@ asmlinkage long sys_accept(int fd, struct sockaddr __user *upeer_sockaddr,
fput_light(sock->file, fput_needed); fput_light(sock->file, fput_needed);
out: out:
return err; return err;
out_fd_simple:
sock_release(newsock);
put_filp(newfile);
put_unused_fd(newfd);
goto out_put;
out_fd: out_fd:
fput(newfile); fput(newfile);
put_unused_fd(newfd); put_unused_fd(newfd);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment