summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.osdl.org>2003-07-25 02:58:59 -0700
committerLinus Torvalds <torvalds@home.osdl.org>2003-07-25 02:58:59 -0700
commit3c6bf5ce5f0554a7e8a8d82036b3dccabd370400 (patch)
tree0dc6057d1dcb9a43d3b5080bb1377ae439f21ec2
parent5ade138f373b988a4eef0698b327a868a7c03b6e (diff)
parent54cdf53bc01532ce8e08f4684526b83adac7ed8a (diff)
Merge bk://kernel.bkbits.net/davem/net-2.5
into home.osdl.org:/home/torvalds/v2.5/linux
-rw-r--r--MAINTAINERS4
-rw-r--r--drivers/net/tg3.c2
-rw-r--r--drivers/pci/pci.ids1
-rw-r--r--include/linux/ipv6_route.h1
-rw-r--r--include/linux/netfilter_bridge/ebtables.h46
-rw-r--r--include/linux/netfilter_ipv4/ipt_REJECT.h3
-rw-r--r--include/linux/pci_ids.h1
-rw-r--r--include/linux/rtnetlink.h51
-rw-r--r--net/atm/lec.c21
-rw-r--r--net/bridge/br_device.c21
-rw-r--r--net/bridge/br_if.c50
-rw-r--r--net/bridge/br_ioctl.c2
-rw-r--r--net/bridge/br_notify.c20
-rw-r--r--net/bridge/br_stp.c18
-rw-r--r--net/bridge/br_stp_if.c5
-rw-r--r--net/bridge/br_stp_timer.c13
-rw-r--r--net/bridge/netfilter/ebt_arp.c2
-rw-r--r--net/bridge/netfilter/ebt_dnat.c2
-rw-r--r--net/bridge/netfilter/ebt_ip.c2
-rw-r--r--net/bridge/netfilter/ebt_log.c2
-rw-r--r--net/bridge/netfilter/ebt_mark.c2
-rw-r--r--net/bridge/netfilter/ebt_mark_m.c2
-rw-r--r--net/bridge/netfilter/ebt_pkttype.c2
-rw-r--r--net/bridge/netfilter/ebt_redirect.c2
-rw-r--r--net/bridge/netfilter/ebt_snat.c2
-rw-r--r--net/bridge/netfilter/ebt_stp.c2
-rw-r--r--net/bridge/netfilter/ebt_vlan.c4
-rw-r--r--net/core/filter.c5
-rw-r--r--net/core/net-sysfs.c2
-rw-r--r--net/core/netfilter.c90
-rw-r--r--net/core/pktgen.c49
-rw-r--r--net/core/rtnetlink.c15
-rw-r--r--net/core/sysctl_net_core.c2
-rw-r--r--net/decnet/af_decnet.c1
-rw-r--r--net/decnet/dn_dev.c1
-rw-r--r--net/decnet/dn_route.c1
-rw-r--r--net/ipv4/ip_output.c2
-rw-r--r--net/ipv4/netfilter/ip_conntrack_core.c13
-rw-r--r--net/ipv4/netfilter/ip_conntrack_irc.c17
-rw-r--r--net/ipv4/netfilter/ipt_MIRROR.c129
-rw-r--r--net/ipv4/netfilter/ipt_REJECT.c299
-rw-r--r--net/ipv4/netfilter/ipt_helper.c14
-rw-r--r--net/ipv6/addrconf.c24
-rw-r--r--net/ipv6/route.c22
44 files changed, 595 insertions, 374 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 790ddb4c535e..1b3d07ec3645 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1632,8 +1632,8 @@ L: linux-scsi@vger.kernel.org
S: Maintained
SCTP PROTOCOL
-P: Jon Grimm
-M: jgrimm2@us.ibm.com
+P: Sridhar Samudrala
+M: sri@us.ibm.com
L: lksctp-developers@lists.sourceforge.net
S: Supported
diff --git a/drivers/net/tg3.c b/drivers/net/tg3.c
index d2a0f9082a63..beed7b3adebe 100644
--- a/drivers/net/tg3.c
+++ b/drivers/net/tg3.c
@@ -154,6 +154,8 @@ static struct pci_device_id tg3_pci_tbl[] __devinitdata = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
+ { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1001,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ 0, }
diff --git a/drivers/pci/pci.ids b/drivers/pci/pci.ids
index 277f087da8cc..174ebf05fe11 100644
--- a/drivers/pci/pci.ids
+++ b/drivers/pci/pci.ids
@@ -5832,6 +5832,7 @@
1737 Linksys
173b Altima (nee Broadcom)
03e8 AC1000 Gigabit Ethernet
+ 03e9 AC1001 Gigabit Ethernet
03ea AC9100 Gigabit Ethernet
1743 Peppercon AG
8139 ROL/F-100 Fast Ethernet Adapter with ROL
diff --git a/include/linux/ipv6_route.h b/include/linux/ipv6_route.h
index eacfa6c80f0e..46d8b7e8b1aa 100644
--- a/include/linux/ipv6_route.h
+++ b/include/linux/ipv6_route.h
@@ -16,6 +16,7 @@
#define RTF_DEFAULT 0x00010000 /* default - learned via ND */
#define RTF_ALLONLINK 0x00020000 /* fallback, no routers on link */
#define RTF_ADDRCONF 0x00040000 /* addrconf route - RA */
+#define RTF_PREFIX_RT 0x00080000 /* A prefix only route - RA */
#define RTF_NONEXTHOP 0x00200000 /* route with no nexthop */
#define RTF_EXPIRES 0x00400000
diff --git a/include/linux/netfilter_bridge/ebtables.h b/include/linux/netfilter_bridge/ebtables.h
index 1056e450ef14..b9fcbf85f047 100644
--- a/include/linux/netfilter_bridge/ebtables.h
+++ b/include/linux/netfilter_bridge/ebtables.h
@@ -33,6 +33,23 @@ struct ebt_counter
uint64_t bcnt;
};
+struct ebt_replace
+{
+ char name[EBT_TABLE_MAXNAMELEN];
+ unsigned int valid_hooks;
+ /* nr of rules in the table */
+ unsigned int nentries;
+ /* total size of the entries */
+ unsigned int entries_size;
+ /* start of the chains */
+ struct ebt_entries *hook_entry[NF_BR_NUMHOOKS];
+ /* nr of counters userspace expects back */
+ unsigned int num_counters;
+ /* where the kernel will put the old counters */
+ struct ebt_counter *counters;
+ char *entries;
+};
+
struct ebt_entries {
/* this field is always set to zero
* See EBT_ENTRY_OR_ENTRIES.
@@ -47,7 +64,7 @@ struct ebt_entries {
/* nr. of entries */
unsigned int nentries;
/* entry list */
- char data[0];
+ char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
};
/* used for the bitmask of struct ebt_entry */
@@ -87,7 +104,7 @@ struct ebt_entry_match
} u;
/* size of data */
unsigned int match_size;
- unsigned char data[0];
+ unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
};
struct ebt_entry_watcher
@@ -98,7 +115,7 @@ struct ebt_entry_watcher
} u;
/* size of data */
unsigned int watcher_size;
- unsigned char data[0];
+ unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
};
struct ebt_entry_target
@@ -109,7 +126,7 @@ struct ebt_entry_target
} u;
/* size of data */
unsigned int target_size;
- unsigned char data[0];
+ unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
};
#define EBT_STANDARD_TARGET "standard"
@@ -143,24 +160,7 @@ struct ebt_entry {
unsigned int target_offset;
/* sizeof ebt_entry + matches + watchers + target */
unsigned int next_offset;
- unsigned char elems[0];
-};
-
-struct ebt_replace
-{
- char name[EBT_TABLE_MAXNAMELEN];
- unsigned int valid_hooks;
- /* nr of rules in the table */
- unsigned int nentries;
- /* total size of the entries */
- unsigned int entries_size;
- /* start of the chains */
- struct ebt_entries *hook_entry[NF_BR_NUMHOOKS];
- /* nr of counters userspace expects back */
- unsigned int num_counters;
- /* where the kernel will put the old counters */
- struct ebt_counter *counters;
- char *entries;
+ unsigned char elems[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
};
/* {g,s}etsockopt numbers */
@@ -263,6 +263,8 @@ struct ebt_table
struct module *me;
};
+#define EBT_ALIGN(s) (((s) + (__alignof__(struct ebt_replace)-1)) & \
+ ~(__alignof__(struct ebt_replace)-1))
extern int ebt_register_table(struct ebt_table *table);
extern void ebt_unregister_table(struct ebt_table *table);
extern int ebt_register_match(struct ebt_match *match);
diff --git a/include/linux/netfilter_ipv4/ipt_REJECT.h b/include/linux/netfilter_ipv4/ipt_REJECT.h
index ad195e435ba9..4293a1ad1b01 100644
--- a/include/linux/netfilter_ipv4/ipt_REJECT.h
+++ b/include/linux/netfilter_ipv4/ipt_REJECT.h
@@ -9,7 +9,8 @@ enum ipt_reject_with {
IPT_ICMP_ECHOREPLY,
IPT_ICMP_NET_PROHIBITED,
IPT_ICMP_HOST_PROHIBITED,
- IPT_TCP_RESET
+ IPT_TCP_RESET,
+ IPT_ICMP_ADMIN_PROHIBITED
};
struct ipt_reject_info {
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index f5184b7f9fdc..7b54e6b44e81 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -1757,6 +1757,7 @@
#define PCI_VENDOR_ID_ALTIMA 0x173b
#define PCI_DEVICE_ID_ALTIMA_AC1000 0x03e8
+#define PCI_DEVICE_ID_ALTIMA_AC1001 0x03e9
#define PCI_DEVICE_ID_ALTIMA_AC9100 0x03ea
#define PCI_VENDOR_ID_SYMPHONY 0x1c1c
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 788132027e48..3e3a26916a12 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -168,6 +168,7 @@ enum rt_scope_t
#define RTM_F_NOTIFY 0x100 /* Notify user of route change */
#define RTM_F_CLONED 0x200 /* This route is cloned */
#define RTM_F_EQUALIZE 0x400 /* Multipath equalizer: NI */
+#define RTM_F_PREFIX 0x800 /* Prefix addresses */
/* Reserved table identifiers */
@@ -458,6 +459,40 @@ struct ifinfomsg
unsigned ifi_change; /* IFF_* change mask */
};
+/* The struct should be in sync with struct net_device_stats */
+struct rtnl_link_stats
+{
+ __u32 rx_packets; /* total packets received */
+ __u32 tx_packets; /* total packets transmitted */
+ __u32 rx_bytes; /* total bytes received */
+ __u32 tx_bytes; /* total bytes transmitted */
+ __u32 rx_errors; /* bad packets received */
+ __u32 tx_errors; /* packet transmit problems */
+ __u32 rx_dropped; /* no space in linux buffers */
+ __u32 tx_dropped; /* no space available in linux */
+ __u32 multicast; /* multicast packets received */
+ __u32 collisions;
+
+ /* detailed rx_errors: */
+ __u32 rx_length_errors;
+ __u32 rx_over_errors; /* receiver ring buff overflow */
+ __u32 rx_crc_errors; /* recved pkt with crc error */
+ __u32 rx_frame_errors; /* recv'd frame alignment error */
+ __u32 rx_fifo_errors; /* recv'r fifo overrun */
+ __u32 rx_missed_errors; /* receiver missed packet */
+
+ /* detailed tx_errors */
+ __u32 tx_aborted_errors;
+ __u32 tx_carrier_errors;
+ __u32 tx_fifo_errors;
+ __u32 tx_heartbeat_errors;
+ __u32 tx_window_errors;
+
+ /* for cslip etc */
+ __u32 rx_compressed;
+ __u32 tx_compressed;
+};
+
enum
{
IFLA_UNSPEC,
@@ -599,6 +634,22 @@ extern void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const voi
({ if (skb_tailroom(skb) < (int)RTA_SPACE(attrlen)) goto rtattr_failure; \
__rta_fill(skb, attrtype, attrlen, data); })
+static inline struct rtattr *
+__rta_reserve(struct sk_buff *skb, int attrtype, int attrlen)
+{
+ struct rtattr *rta;
+ int size = RTA_LENGTH(attrlen);
+
+ rta = (struct rtattr*)skb_put(skb, RTA_ALIGN(size));
+ rta->rta_type = attrtype;
+ rta->rta_len = size;
+ return rta;
+}
+
+#define __RTA_PUT(skb, attrtype, attrlen) \
+({ if (skb_tailroom(skb) < (int)RTA_SPACE(attrlen)) goto rtattr_failure; \
+ __rta_reserve(skb, attrtype, attrlen); })
+
extern void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change);
extern struct semaphore rtnl_sem;
diff --git a/net/atm/lec.c b/net/atm/lec.c
index cc075949cd30..67228a48527d 100644
--- a/net/atm/lec.c
+++ b/net/atm/lec.c
@@ -1031,7 +1031,7 @@ static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr,
#define LEC_ARP_REFRESH_INTERVAL (3*HZ)
static void lec_arp_check_expire(unsigned long data);
-static __inline__ void lec_arp_expire_arp(unsigned long data);
+static void lec_arp_expire_arp(unsigned long data);
void dump_arp_table(struct lec_priv *priv);
/*
@@ -1371,7 +1371,7 @@ lec_arp_destroy(struct lec_priv *priv)
struct lec_arp_table *entry, *next;
int i;
- del_timer(&priv->lec_arp_timer);
+ del_timer_sync(&priv->lec_arp_timer);
/*
* Remove all entries
@@ -1386,7 +1386,7 @@ lec_arp_destroy(struct lec_priv *priv)
entry = priv->lec_arp_empty_ones;
while(entry) {
next = entry->next;
- del_timer(&entry->timer);
+ del_timer_sync(&entry->timer);
lec_arp_clear_vccs(entry);
kfree(entry);
entry = next;
@@ -1395,7 +1395,7 @@ lec_arp_destroy(struct lec_priv *priv)
entry = priv->lec_no_forward;
while(entry) {
next = entry->next;
- del_timer(&entry->timer);
+ del_timer_sync(&entry->timer);
lec_arp_clear_vccs(entry);
kfree(entry);
entry = next;
@@ -1404,7 +1404,7 @@ lec_arp_destroy(struct lec_priv *priv)
entry = priv->mcast_fwds;
while(entry) {
next = entry->next;
- del_timer(&entry->timer);
+ /* No timer, LANEv2 7.1.20 and 2.3.5.3 */
lec_arp_clear_vccs(entry);
kfree(entry);
entry = next;
@@ -1478,8 +1478,6 @@ lec_arp_expire_arp(unsigned long data)
entry = (struct lec_arp_table *)data;
- del_timer(&entry->timer);
-
DPRINTK("lec_arp_expire_arp\n");
if (entry->status == ESI_ARP_PENDING) {
if (entry->no_tries <= entry->priv->max_retry_count) {
@@ -1489,8 +1487,7 @@ lec_arp_expire_arp(unsigned long data)
send_to_lecd(entry->priv, l_arp_xmt, entry->mac_addr, NULL, NULL);
entry->no_tries++;
}
- entry->timer.expires = jiffies + (1*HZ);
- add_timer(&entry->timer);
+ mod_timer(&entry->timer, jiffies + (1*HZ));
}
}
@@ -1562,8 +1559,6 @@ lec_arp_check_expire(unsigned long data)
unsigned long time_to_check;
int i;
- del_timer(&priv->lec_arp_timer);
-
DPRINTK("lec_arp_check_expire %p,%d\n",priv,
atomic_read(&priv->lec_arp_users));
DPRINTK("expire: eo:%p nf:%p\n",priv->lec_arp_empty_ones,
@@ -1621,8 +1616,8 @@ lec_arp_check_expire(unsigned long data)
}
lec_arp_put(priv);
}
- priv->lec_arp_timer.expires = jiffies + LEC_ARP_REFRESH_INTERVAL;
- add_timer(&priv->lec_arp_timer);
+
+ mod_timer(&priv->lec_arp_timer, jiffies + LEC_ARP_REFRESH_INTERVAL);
}
/*
* Try to find vcc where mac_address is attached.
diff --git a/net/bridge/br_device.c b/net/bridge/br_device.c
index b4e92cb875c6..36d02b08989d 100644
--- a/net/bridge/br_device.c
+++ b/net/bridge/br_device.c
@@ -110,23 +110,38 @@ static int br_dev_accept_fastpath(struct net_device *dev, struct dst_entry *dst)
return -1;
}
+/* convert later to direct kfree */
+static void br_dev_free(struct net_device *dev)
+{
+ struct net_bridge *br = dev->priv;
+
+ WARN_ON(!list_empty(&br->port_list));
+ WARN_ON(!list_empty(&br->age_list));
+
+ BUG_ON(timer_pending(&br->hello_timer));
+ BUG_ON(timer_pending(&br->tcn_timer));
+ BUG_ON(timer_pending(&br->topology_change_timer));
+ BUG_ON(timer_pending(&br->gc_timer));
+
+ kfree(dev);
+}
void br_dev_setup(struct net_device *dev)
{
memset(dev->dev_addr, 0, ETH_ALEN);
+ ether_setup(dev);
+
dev->do_ioctl = br_dev_do_ioctl;
dev->get_stats = br_dev_get_stats;
dev->hard_start_xmit = br_dev_xmit;
dev->open = br_dev_open;
dev->set_multicast_list = br_dev_set_multicast_list;
- dev->destructor = (void (*)(struct net_device *))kfree;
+ dev->destructor = br_dev_free;
SET_MODULE_OWNER(dev);
dev->stop = br_dev_stop;
dev->accept_fastpath = br_dev_accept_fastpath;
dev->tx_queue_len = 0;
dev->set_mac_address = NULL;
dev->priv_flags = IFF_EBRIDGE;
-
- ether_setup(dev);
}
diff --git a/net/bridge/br_if.c b/net/bridge/br_if.c
index cbfa8653f210..220b97a09921 100644
--- a/net/bridge/br_if.c
+++ b/net/bridge/br_if.c
@@ -41,6 +41,13 @@ static int br_initial_port_cost(struct net_device *dev)
static void destroy_nbp(void *arg)
{
struct net_bridge_port *p = arg;
+
+ p->dev->br_port = NULL;
+
+ BUG_ON(timer_pending(&p->message_age_timer));
+ BUG_ON(timer_pending(&p->forward_delay_timer));
+ BUG_ON(timer_pending(&p->hold_timer));
+
dev_put(p->dev);
kfree(p);
}
@@ -53,16 +60,19 @@ static void del_nbp(struct net_bridge_port *p)
br_stp_disable_port(p);
dev_set_promiscuity(dev, -1);
- dev->br_port = NULL;
list_del_rcu(&p->list);
br_fdb_delete_by_port(p->br, p);
+ del_timer(&p->message_age_timer);
+ del_timer(&p->forward_delay_timer);
+ del_timer(&p->hold_timer);
+
call_rcu(&p->rcu, destroy_nbp, p);
}
-static void del_ifs(struct net_bridge *br)
+static void del_br(struct net_bridge *br)
{
struct list_head *p, *n;
@@ -71,6 +81,10 @@ static void del_ifs(struct net_bridge *br)
del_nbp(list_entry(p, struct net_bridge_port, list));
}
spin_unlock_bh(&br->lock);
+
+ del_timer_sync(&br->gc_timer);
+
+ unregister_netdevice(br->dev);
}
static struct net_bridge *new_nb(const char *name)
@@ -182,15 +196,14 @@ int br_del_bridge(const char *name)
ret = -EBUSY;
}
- else {
- del_ifs((struct net_bridge *) dev->priv);
- unregister_netdevice(dev);
- }
+ else
+ del_br(dev->priv);
rtnl_unlock();
return ret;
}
+/* called under bridge lock */
int br_add_if(struct net_bridge *br, struct net_device *dev)
{
struct net_bridge_port *p;
@@ -205,7 +218,6 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
return -ELOOP;
dev_hold(dev);
- spin_lock_bh(&br->lock);
if ((p = new_nbp(br, dev)) == NULL) {
spin_unlock_bh(&br->lock);
dev_put(dev);
@@ -218,26 +230,21 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
br_fdb_insert(br, p, dev->dev_addr, 1);
if ((br->dev->flags & IFF_UP) && (dev->flags & IFF_UP))
br_stp_enable_port(p);
- spin_unlock_bh(&br->lock);
return 0;
}
+/* called under bridge lock */
int br_del_if(struct net_bridge *br, struct net_device *dev)
{
struct net_bridge_port *p;
- int retval = 0;
- spin_lock_bh(&br->lock);
if ((p = dev->br_port) == NULL || p->br != br)
- retval = -EINVAL;
- else {
- del_nbp(p);
- br_stp_recalculate_bridge_id(br);
- }
- spin_unlock_bh(&br->lock);
+ return -EINVAL;
- return retval;
+ del_nbp(p);
+ br_stp_recalculate_bridge_id(br);
+ return 0;
}
int br_get_bridge_ifindices(int *indices, int num)
@@ -274,13 +281,8 @@ void __exit br_cleanup_bridges(void)
rtnl_lock();
for (dev = dev_base; dev; dev = nxt) {
nxt = dev->next;
- if (dev->priv_flags & IFF_EBRIDGE) {
- pr_debug("cleanup %s\n", dev->name);
-
- del_ifs((struct net_bridge *) dev->priv);
-
- unregister_netdevice(dev);
- }
+ if (dev->priv_flags & IFF_EBRIDGE)
+ del_br(dev->priv);
}
rtnl_unlock();
diff --git a/net/bridge/br_ioctl.c b/net/bridge/br_ioctl.c
index 939663847ca4..3ee2e2e8361d 100644
--- a/net/bridge/br_ioctl.c
+++ b/net/bridge/br_ioctl.c
@@ -59,10 +59,12 @@ static int br_ioctl_device(struct net_bridge *br,
if (dev == NULL)
return -EINVAL;
+ spin_lock_bh(&br->lock);
if (cmd == BRCTL_ADD_IF)
ret = br_add_if(br, dev);
else
ret = br_del_if(br, dev);
+ spin_unlock_bh(&br->lock);
dev_put(dev);
return ret;
diff --git a/net/bridge/br_notify.c b/net/bridge/br_notify.c
index 72cc91e87523..9993944c56cf 100644
--- a/net/bridge/br_notify.c
+++ b/net/bridge/br_notify.c
@@ -38,39 +38,27 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
br = p->br;
+ spin_lock_bh(&br->lock);
switch (event)
{
case NETDEV_CHANGEADDR:
- spin_lock_bh(&br->lock);
br_fdb_changeaddr(p, dev->dev_addr);
br_stp_recalculate_bridge_id(br);
- spin_unlock_bh(&br->lock);
- break;
-
- case NETDEV_GOING_DOWN:
- /* extend the protocol to send some kind of notification? */
break;
case NETDEV_DOWN:
- if (br->dev->flags & IFF_UP) {
- spin_lock_bh(&br->lock);
- br_stp_disable_port(p);
- spin_unlock_bh(&br->lock);
- }
+ br_stp_disable_port(p);
break;
case NETDEV_UP:
- if (!(br->dev->flags & IFF_UP)) {
- spin_lock_bh(&br->lock);
- br_stp_enable_port(p);
- spin_unlock_bh(&br->lock);
- }
+ br_stp_enable_port(p);
break;
case NETDEV_UNREGISTER:
br_del_if(br, dev);
break;
}
+ spin_unlock_bh(&br->lock);
return NOTIFY_DONE;
}
diff --git a/net/bridge/br_stp.c b/net/bridge/br_stp.c
index 26e5ef0e7d92..b833444f9fa4 100644
--- a/net/bridge/br_stp.c
+++ b/net/bridge/br_stp.c
@@ -20,7 +20,11 @@
#include "br_private_stp.h"
static const char *br_port_state_names[] = {
- "disabled", "learning", "forwarding", "blocking",
+ [BR_STATE_DISABLED] = "disabled",
+ [BR_STATE_LISTENING] = "listening",
+ [BR_STATE_LEARNING] = "learning",
+ [BR_STATE_FORWARDING] = "forwarding",
+ [BR_STATE_BLOCKING] = "blocking",
};
void br_log_state(const struct net_bridge_port *p)
@@ -289,22 +293,20 @@ static inline void br_topology_change_acknowledged(struct net_bridge *br)
/* called under bridge lock */
void br_topology_change_detection(struct net_bridge *br)
{
- if (!(br->dev->flags & IFF_UP))
- return;
+ int isroot = br_is_root_bridge(br);
+
+ pr_info("%s: topology change detected, %s\n", br->dev->name,
+ isroot ? "propgating" : "sending tcn bpdu");
- pr_info("%s: topology change detected", br->dev->name);
- if (br_is_root_bridge(br)) {
- printk(", propagating");
+ if (isroot) {
br->topology_change = 1;
mod_timer(&br->topology_change_timer, jiffies
+ br->bridge_forward_delay + br->bridge_max_age);
} else if (!br->topology_change_detected) {
- printk(", sending tcn bpdu");
br_transmit_tcn(br);
mod_timer(&br->tcn_timer, jiffies + br->bridge_hello_time);
}
- printk("\n");
br->topology_change_detected = 1;
}
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c
index f644f2164a5e..c3a906a1159c 100644
--- a/net/bridge/br_stp_if.c
+++ b/net/bridge/br_stp_if.c
@@ -43,8 +43,7 @@ void br_stp_enable_bridge(struct net_bridge *br)
struct net_bridge_port *p;
spin_lock_bh(&br->lock);
- br->hello_timer.expires = jiffies + br->hello_time;
- add_timer(&br->hello_timer);
+ mod_timer(&br->hello_timer, jiffies + br->hello_time);
br_config_bpdu_generation(br);
list_for_each_entry(p, &br->port_list, list) {
@@ -74,8 +73,6 @@ void br_stp_disable_bridge(struct net_bridge *br)
del_timer_sync(&br->hello_timer);
del_timer_sync(&br->topology_change_timer);
del_timer_sync(&br->tcn_timer);
- del_timer_sync(&br->gc_timer);
-
}
/* called under bridge lock */
diff --git a/net/bridge/br_stp_timer.c b/net/bridge/br_stp_timer.c
index a5a75cede729..eb106a4042fd 100644
--- a/net/bridge/br_stp_timer.c
+++ b/net/bridge/br_stp_timer.c
@@ -43,8 +43,7 @@ static void br_hello_timer_expired(unsigned long arg)
if (br->dev->flags & IFF_UP) {
br_config_bpdu_generation(br);
- br->hello_timer.expires = jiffies + br->hello_time;
- add_timer(&br->hello_timer);
+ mod_timer(&br->hello_timer, jiffies + br->hello_time);
}
spin_unlock_bh(&br->lock);
}
@@ -73,6 +72,8 @@ static void br_message_age_timer_expired(unsigned long arg)
* check is redundant. I'm leaving it in for now, though.
*/
spin_lock_bh(&br->lock);
+ if (p->state == BR_STATE_DISABLED)
+ goto unlock;
was_root = br_is_root_bridge(br);
br_become_designated_port(p);
@@ -80,6 +81,7 @@ static void br_message_age_timer_expired(unsigned long arg)
br_port_state_selection(br);
if (br_is_root_bridge(br) && !was_root)
br_become_root_bridge(br);
+ unlock:
spin_unlock_bh(&br->lock);
}
@@ -93,8 +95,8 @@ static void br_forward_delay_timer_expired(unsigned long arg)
spin_lock_bh(&br->lock);
if (p->state == BR_STATE_LISTENING) {
p->state = BR_STATE_LEARNING;
- p->forward_delay_timer.expires = jiffies + br->forward_delay;
- add_timer(&p->forward_delay_timer);
+ mod_timer(&p->forward_delay_timer,
+ jiffies + br->forward_delay);
} else if (p->state == BR_STATE_LEARNING) {
p->state = BR_STATE_FORWARDING;
if (br_is_designated_for_some_port(br))
@@ -113,8 +115,7 @@ static void br_tcn_timer_expired(unsigned long arg)
if (br->dev->flags & IFF_UP) {
br_transmit_tcn(br);
- br->tcn_timer.expires = jiffies + br->bridge_hello_time;
- add_timer(&br->tcn_timer);
+ mod_timer(&br->tcn_timer,jiffies + br->bridge_hello_time);
}
spin_unlock_bh(&br->lock);
}
diff --git a/net/bridge/netfilter/ebt_arp.c b/net/bridge/netfilter/ebt_arp.c
index d63d7206bbcb..eb675848fbc3 100644
--- a/net/bridge/netfilter/ebt_arp.c
+++ b/net/bridge/netfilter/ebt_arp.c
@@ -99,7 +99,7 @@ static int ebt_arp_check(const char *tablename, unsigned int hookmask,
{
struct ebt_arp_info *info = (struct ebt_arp_info *)data;
- if (datalen != sizeof(struct ebt_arp_info))
+ if (datalen != EBT_ALIGN(sizeof(struct ebt_arp_info)))
return -EINVAL;
if ((e->ethproto != __constant_htons(ETH_P_ARP) &&
e->ethproto != __constant_htons(ETH_P_RARP)) ||
diff --git a/net/bridge/netfilter/ebt_dnat.c b/net/bridge/netfilter/ebt_dnat.c
index c8b3357cc090..f9552dfb1655 100644
--- a/net/bridge/netfilter/ebt_dnat.c
+++ b/net/bridge/netfilter/ebt_dnat.c
@@ -47,7 +47,7 @@ static int ebt_target_dnat_check(const char *tablename, unsigned int hookmask,
(hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))) &&
(strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) )
return -EINVAL;
- if (datalen != sizeof(struct ebt_nat_info))
+ if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info)))
return -EINVAL;
if (INVALID_TARGET)
return -EINVAL;
diff --git a/net/bridge/netfilter/ebt_ip.c b/net/bridge/netfilter/ebt_ip.c
index 7ef0662f81c6..7bab7d065bd3 100644
--- a/net/bridge/netfilter/ebt_ip.c
+++ b/net/bridge/netfilter/ebt_ip.c
@@ -75,7 +75,7 @@ static int ebt_ip_check(const char *tablename, unsigned int hookmask,
{
struct ebt_ip_info *info = (struct ebt_ip_info *)data;
- if (datalen != sizeof(struct ebt_ip_info))
+ if (datalen != EBT_ALIGN(sizeof(struct ebt_ip_info)))
return -EINVAL;
if (e->ethproto != __constant_htons(ETH_P_IP) ||
e->invflags & EBT_IPROTO)
diff --git a/net/bridge/netfilter/ebt_log.c b/net/bridge/netfilter/ebt_log.c
index e7a3ef4afe5a..2da7c682744d 100644
--- a/net/bridge/netfilter/ebt_log.c
+++ b/net/bridge/netfilter/ebt_log.c
@@ -22,7 +22,7 @@ static int ebt_log_check(const char *tablename, unsigned int hookmask,
{
struct ebt_log_info *info = (struct ebt_log_info *)data;
- if (datalen != sizeof(struct ebt_log_info))
+ if (datalen != EBT_ALIGN(sizeof(struct ebt_log_info)))
return -EINVAL;
if (info->bitmask & ~EBT_LOG_MASK)
return -EINVAL;
diff --git a/net/bridge/netfilter/ebt_mark.c b/net/bridge/netfilter/ebt_mark.c
index b7a87f612983..02c632b4d325 100644
--- a/net/bridge/netfilter/ebt_mark.c
+++ b/net/bridge/netfilter/ebt_mark.c
@@ -35,7 +35,7 @@ static int ebt_target_mark_check(const char *tablename, unsigned int hookmask,
{
struct ebt_mark_t_info *info = (struct ebt_mark_t_info *)data;
- if (datalen != sizeof(struct ebt_mark_t_info))
+ if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_t_info)))
return -EINVAL;
if (BASE_CHAIN && info->target == EBT_RETURN)
return -EINVAL;
diff --git a/net/bridge/netfilter/ebt_mark_m.c b/net/bridge/netfilter/ebt_mark_m.c
index c710b4e0be14..625102de1495 100644
--- a/net/bridge/netfilter/ebt_mark_m.c
+++ b/net/bridge/netfilter/ebt_mark_m.c
@@ -28,7 +28,7 @@ static int ebt_mark_check(const char *tablename, unsigned int hookmask,
{
struct ebt_mark_m_info *info = (struct ebt_mark_m_info *) data;
- if (datalen != sizeof(struct ebt_mark_m_info))
+ if (datalen != EBT_ALIGN(sizeof(struct ebt_mark_m_info)))
return -EINVAL;
if (info->bitmask & ~EBT_MARK_MASK)
return -EINVAL;
diff --git a/net/bridge/netfilter/ebt_pkttype.c b/net/bridge/netfilter/ebt_pkttype.c
index f6458adea80a..ecd3b42b19b0 100644
--- a/net/bridge/netfilter/ebt_pkttype.c
+++ b/net/bridge/netfilter/ebt_pkttype.c
@@ -28,7 +28,7 @@ static int ebt_pkttype_check(const char *tablename, unsigned int hookmask,
{
struct ebt_pkttype_info *info = (struct ebt_pkttype_info *)data;
- if (datalen != sizeof(struct ebt_pkttype_info))
+ if (datalen != EBT_ALIGN(sizeof(struct ebt_pkttype_info)))
return -EINVAL;
if (info->invert != 0 && info->invert != 1)
return -EINVAL;
diff --git a/net/bridge/netfilter/ebt_redirect.c b/net/bridge/netfilter/ebt_redirect.c
index d97d05fdd14f..998bab1c5ef9 100644
--- a/net/bridge/netfilter/ebt_redirect.c
+++ b/net/bridge/netfilter/ebt_redirect.c
@@ -47,7 +47,7 @@ static int ebt_target_redirect_check(const char *tablename, unsigned int hookmas
{
struct ebt_redirect_info *info = (struct ebt_redirect_info *)data;
- if (datalen != sizeof(struct ebt_redirect_info))
+ if (datalen != EBT_ALIGN(sizeof(struct ebt_redirect_info)))
return -EINVAL;
if (BASE_CHAIN && info->target == EBT_RETURN)
return -EINVAL;
diff --git a/net/bridge/netfilter/ebt_snat.c b/net/bridge/netfilter/ebt_snat.c
index c457ac90c5c6..ae0f0539c5f0 100644
--- a/net/bridge/netfilter/ebt_snat.c
+++ b/net/bridge/netfilter/ebt_snat.c
@@ -40,7 +40,7 @@ static int ebt_target_snat_check(const char *tablename, unsigned int hookmask,
{
struct ebt_nat_info *info = (struct ebt_nat_info *) data;
- if (datalen != sizeof(struct ebt_nat_info))
+ if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info)))
return -EINVAL;
if (BASE_CHAIN && info->target == EBT_RETURN)
return -EINVAL;
diff --git a/net/bridge/netfilter/ebt_stp.c b/net/bridge/netfilter/ebt_stp.c
index 8be478935ba8..d0299efa1001 100644
--- a/net/bridge/netfilter/ebt_stp.c
+++ b/net/bridge/netfilter/ebt_stp.c
@@ -150,7 +150,7 @@ static int ebt_stp_check(const char *tablename, unsigned int hookmask,
const struct ebt_entry *e, void *data, unsigned int datalen)
{
struct ebt_stp_info *info = (struct ebt_stp_info *)data;
- int len = sizeof(struct ebt_stp_info);
+ int len = EBT_ALIGN(sizeof(struct ebt_stp_info));
uint8_t bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
uint8_t msk[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
diff --git a/net/bridge/netfilter/ebt_vlan.c b/net/bridge/netfilter/ebt_vlan.c
index 54120a771d3e..341af7d5708b 100644
--- a/net/bridge/netfilter/ebt_vlan.c
+++ b/net/bridge/netfilter/ebt_vlan.c
@@ -35,7 +35,7 @@ MODULE_DESCRIPTION("802.1Q match module (ebtables extension), v"
MODULE_LICENSE("GPL");
-#define DEBUG_MSG(...) if (debug) printk (KERN_DEBUG "ebt_vlan: " __VA_ARGS__)
+#define DEBUG_MSG(args...) if (debug) printk (KERN_DEBUG "ebt_vlan: " args)
#define INV_FLAG(_inv_flag_) (info->invflags & _inv_flag_) ? "!" : ""
#define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_
#define SET_BITMASK(_BIT_MASK_) info->bitmask |= _BIT_MASK_
@@ -94,7 +94,7 @@ ebt_check_vlan(const char *tablename,
struct ebt_vlan_info *info = (struct ebt_vlan_info *) data;
/* Parameters buffer overflow check */
- if (datalen != sizeof(struct ebt_vlan_info)) {
+ if (datalen != EBT_ALIGN(sizeof(struct ebt_vlan_info))) {
DEBUG_MSG
("passed size %d is not eq to ebt_vlan_info (%Zd)\n",
datalen, sizeof(struct ebt_vlan_info));
diff --git a/net/core/filter.c b/net/core/filter.c
index 3bb1e4669ba5..5b2a5b785462 100644
--- a/net/core/filter.c
+++ b/net/core/filter.c
@@ -256,10 +256,9 @@ load_b:
k = X + fentry->k;
goto load_b;
case BPF_LDX|BPF_B|BPF_MSH:
- k = fentry->k;
- if (k >= 0 && (unsigned int)k >= len)
+ if (fentry->k >= len)
return 0;
- X = (data[k] & 0xf) << 2;
+ X = (data[fentry->k] & 0xf) << 2;
continue;
case BPF_LD|BPF_IMM:
A = fentry->k;
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index fcb38de5ad40..e163036c3f83 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -186,7 +186,7 @@ struct netstat_fs_entry {
static ssize_t net_device_stat_show(unsigned long var, char *buf)
{
- return sprintf(buf, "%ld\n", var);
+ return sprintf(buf, "%lu\n", var);
}
/* generate a read-only statistics attribute */
diff --git a/net/core/netfilter.c b/net/core/netfilter.c
index 1c08a5bfae90..980cd4514d69 100644
--- a/net/core/netfilter.c
+++ b/net/core/netfilter.c
@@ -625,66 +625,62 @@ int ip_route_me_harder(struct sk_buff **pskb)
{
struct iphdr *iph = (*pskb)->nh.iph;
struct rtable *rt;
- struct flowi fl = { .nl_u = { .ip4_u =
- { .daddr = iph->daddr,
- .saddr = iph->saddr,
- .tos = RT_TOS(iph->tos)|RTO_CONN,
-#ifdef CONFIG_IP_ROUTE_FWMARK
- .fwmark = (*pskb)->nfmark
-#endif
- } },
- .oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0,
- };
- struct net_device *dev_src = NULL;
- int err;
-
- /* accommodate ip_route_output_slow(), which expects the key src to be
- 0 or a local address; however some non-standard hacks like
- ipt_REJECT.c:send_reset() can cause packets with foreign
- saddr to be appear on the NF_IP_LOCAL_OUT hook -MB */
- if(fl.fl4_src && !(dev_src = ip_dev_find(fl.fl4_src)))
- fl.fl4_src = 0;
-
- if ((err=ip_route_output_key(&rt, &fl)) != 0) {
- printk("route_me_harder: ip_route_output_key(dst=%u.%u.%u.%u, src=%u.%u.%u.%u, oif=%d, tos=0x%x, fwmark=0x%lx) error %d\n",
- NIPQUAD(iph->daddr), NIPQUAD(iph->saddr),
- (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0,
- RT_TOS(iph->tos)|RTO_CONN,
+ struct flowi fl = {};
+ struct dst_entry *odst;
+ unsigned int hh_len;
+
+ /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
+ * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook.
+ */
+ if (inet_addr_type(iph->saddr) == RTN_LOCAL) {
+ fl.nl_u.ip4_u.daddr = iph->daddr;
+ fl.nl_u.ip4_u.saddr = iph->saddr;
+ fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
+ fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0;
#ifdef CONFIG_IP_ROUTE_FWMARK
- (*pskb)->nfmark,
-#else
- 0UL,
+ fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark;
#endif
- err);
- goto out;
- }
+ if (ip_route_output_key(&rt, &fl) != 0)
+ return -1;
- /* Drop old route. */
- dst_release((*pskb)->dst);
-
- (*pskb)->dst = &rt->u.dst;
+ /* Drop old route. */
+ dst_release((*pskb)->dst);
+ (*pskb)->dst = &rt->u.dst;
+ } else {
+ /* non-local src, find valid iif to satisfy
+ * rp-filter when calling ip_route_input. */
+ fl.nl_u.ip4_u.daddr = iph->saddr;
+ if (ip_route_output_key(&rt, &fl) != 0)
+ return -1;
+
+ odst = (*pskb)->dst;
+ if (ip_route_input(*pskb, iph->daddr, iph->saddr,
+ RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
+ dst_release(&rt->u.dst);
+ return -1;
+ }
+ dst_release(&rt->u.dst);
+ dst_release(odst);
+ }
+
+ if ((*pskb)->dst->error)
+ return -1;
/* Change in oif may mean change in hh_len. */
- if (skb_headroom(*pskb) < (*pskb)->dst->dev->hard_header_len) {
+ hh_len = (*pskb)->dst->dev->hard_header_len;
+ if (skb_headroom(*pskb) < hh_len) {
struct sk_buff *nskb;
- nskb = skb_realloc_headroom(*pskb,
- (*pskb)->dst->dev->hard_header_len);
- if (!nskb) {
- err = -ENOMEM;
- goto out;
- }
+ nskb = skb_realloc_headroom(*pskb, hh_len);
+ if (!nskb)
+ return -1;
if ((*pskb)->sk)
skb_set_owner_w(nskb, (*pskb)->sk);
kfree_skb(*pskb);
*pskb = nskb;
}
-out:
- if (dev_src)
- dev_put(dev_src);
-
- return err;
+ return 0;
}
int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
diff --git a/net/core/pktgen.c b/net/core/pktgen.c
index 2fd263454969..0652fdaf9079 100644
--- a/net/core/pktgen.c
+++ b/net/core/pktgen.c
@@ -47,6 +47,9 @@
* Also moved to /proc/net/pktgen/
* --ro
*
+ * Fix refcount off by one if first packet fails, potential null deref,
+ * memleak 030710- KJP
+ *
* See Documentation/networking/pktgen.txt for how to use this.
*/
@@ -85,9 +88,9 @@
#define cycles() ((u32)get_cycles())
-#define VERSION "pktgen version 1.2"
+#define VERSION "pktgen version 1.3"
static char version[] __initdata =
- "pktgen.c: v1.2: Packet Generator for packet performance testing.\n";
+ "pktgen.c: v1.3: Packet Generator for packet performance testing.\n";
/* Used to help with determining the pkts on receive */
@@ -611,12 +614,11 @@ static void inject(struct pktgen_info* info)
kfree_skb(skb);
skb = fill_packet(odev, info);
if (skb == NULL) {
- break;
+ goto out_reldev;
}
fp++;
fp_tmp = 0; /* reset counter */
}
- atomic_inc(&skb->users);
}
nr_frags = skb_shinfo(skb)->nr_frags;
@@ -624,7 +626,11 @@ static void inject(struct pktgen_info* info)
spin_lock_bh(&odev->xmit_lock);
if (!netif_queue_stopped(odev)) {
+ atomic_inc(&skb->users);
+
if (odev->hard_start_xmit(skb, odev)) {
+
+ atomic_dec(&skb->users);
if (net_ratelimit()) {
printk(KERN_INFO "Hard xmit error\n");
}
@@ -729,15 +735,15 @@ static void inject(struct pktgen_info* info)
(unsigned long long) info->errors
);
}
-
+
+ kfree_skb(skb);
+
out_reldev:
if (odev) {
dev_put(odev);
odev = NULL;
}
- /* TODO: Is this worth printing out (other than for debug?) */
- printk("fp = %llu\n", (unsigned long long) fp);
return;
}
@@ -953,7 +959,8 @@ static int proc_write(struct file *file, const char *user_buffer,
if (len < 0)
return len;
memset(name, 0, sizeof(name));
- copy_from_user(name, &user_buffer[i], len);
+ if (copy_from_user(name, &user_buffer[i], len))
+ return -EFAULT;
i += len;
max = count -i;
@@ -1083,18 +1090,20 @@ static int proc_write(struct file *file, const char *user_buffer,
if (len < 0)
return len;
memset(info->outdev, 0, sizeof(info->outdev));
- copy_from_user(info->outdev, &user_buffer[i], len);
+ if (copy_from_user(info->outdev, &user_buffer[i], len))
+ return -EFAULT;
i += len;
sprintf(result, "OK: odev=%s", info->outdev);
return count;
}
if (!strcmp(name, "flag")) {
char f[32];
- memset(f, 0, 32);
len = strn_len(&user_buffer[i], sizeof(f) - 1);
if (len < 0)
return len;
- copy_from_user(f, &user_buffer[i], len);
+ memset(f, 0, 32);
+ if (copy_from_user(f, &user_buffer[i], len))
+ return -EFAULT;
i += len;
if (strcmp(f, "IPSRC_RND") == 0) {
info->flags |= F_IPSRC_RND;
@@ -1146,7 +1155,8 @@ static int proc_write(struct file *file, const char *user_buffer,
if (len < 0)
return len;
memset(info->dst_min, 0, sizeof(info->dst_min));
- copy_from_user(info->dst_min, &user_buffer[i], len);
+ if (copy_from_user(info->dst_min, &user_buffer[i], len))
+ return -EFAULT;
if(debug)
printk("pg: dst_min set to: %s\n", info->dst_min);
i += len;
@@ -1158,7 +1168,8 @@ static int proc_write(struct file *file, const char *user_buffer,
if (len < 0)
return len;
memset(info->dst_max, 0, sizeof(info->dst_max));
- copy_from_user(info->dst_max, &user_buffer[i], len);
+ if (copy_from_user(info->dst_max, &user_buffer[i], len))
+ return -EFAULT;
if(debug)
printk("pg: dst_max set to: %s\n", info->dst_max);
i += len;
@@ -1170,7 +1181,8 @@ static int proc_write(struct file *file, const char *user_buffer,
if (len < 0)
return len;
memset(info->src_min, 0, sizeof(info->src_min));
- copy_from_user(info->src_min, &user_buffer[i], len);
+ if (copy_from_user(info->src_min, &user_buffer[i], len))
+ return -EFAULT;
if(debug)
printk("pg: src_min set to: %s\n", info->src_min);
i += len;
@@ -1182,7 +1194,8 @@ static int proc_write(struct file *file, const char *user_buffer,
if (len < 0)
return len;
memset(info->src_max, 0, sizeof(info->src_max));
- copy_from_user(info->src_max, &user_buffer[i], len);
+ if (copy_from_user(info->src_max, &user_buffer[i], len))
+ return -EFAULT;
if(debug)
printk("pg: src_max set to: %s\n", info->src_max);
i += len;
@@ -1197,7 +1210,8 @@ static int proc_write(struct file *file, const char *user_buffer,
if (len < 0)
return len;
memset(valstr, 0, sizeof(valstr));
- copy_from_user(valstr, &user_buffer[i], len);
+ if (copy_from_user(valstr, &user_buffer[i], len))
+ return -EFAULT;
i += len;
for(*m = 0;*v && m < info->dst_mac + 6; v++) {
@@ -1229,7 +1243,8 @@ static int proc_write(struct file *file, const char *user_buffer,
if (len < 0)
return len;
memset(valstr, 0, sizeof(valstr));
- copy_from_user(valstr, &user_buffer[i], len);
+ if (copy_from_user(valstr, &user_buffer[i], len))
+ return -EFAULT;
i += len;
for(*m = 0;*v && m < info->src_mac + 6; v++) {
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 32e64ed866a3..4215e4a7dcd0 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -191,9 +191,18 @@ static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
if (dev->master)
RTA_PUT(skb, IFLA_MASTER, sizeof(int), &dev->master->ifindex);
if (dev->get_stats) {
- struct net_device_stats *stats = dev->get_stats(dev);
- if (stats)
- RTA_PUT(skb, IFLA_STATS, sizeof(*stats), stats);
+ unsigned long *stats = (unsigned long*)dev->get_stats(dev);
+ if (stats) {
+ struct rtattr *a;
+ __u32 *s;
+ int i;
+ int n = sizeof(struct rtnl_link_stats)/4;
+
+ a = __RTA_PUT(skb, IFLA_STATS, n*4);
+ s = RTA_DATA(a);
+ for (i=0; i<n; i++)
+ s[i] = stats[i];
+ }
}
nlh->nlmsg_len = skb->tail - b;
return skb->len;
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 3e38ed82429b..9ea7856f9fbc 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -86,7 +86,7 @@ ctl_table core_table[] = {
{
.ctl_name = NET_CORE_NO_CONG_THRESH,
.procname = "no_cong_thresh",
- .data = &no_cong,
+ .data = &no_cong_thresh,
.maxlen = sizeof(int),
.mode = 0644,
.proc_handler = &proc_dointvec
diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c
index 318740b029d6..296938c8cfca 100644
--- a/net/decnet/af_decnet.c
+++ b/net/decnet/af_decnet.c
@@ -2308,6 +2308,7 @@ out_kfree:
}
static struct file_operations dn_socket_seq_fops = {
+ .owner = THIS_MODULE,
.open = dn_socket_seq_open,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/net/decnet/dn_dev.c b/net/decnet/dn_dev.c
index 63fdae09b071..2b8050dc1cd3 100644
--- a/net/decnet/dn_dev.c
+++ b/net/decnet/dn_dev.c
@@ -1443,6 +1443,7 @@ static int dn_dev_seq_open(struct inode *inode, struct file *file)
}
static struct file_operations dn_dev_seq_fops = {
+ .owner = THIS_MODULE,
.open = dn_dev_seq_open,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/net/decnet/dn_route.c b/net/decnet/dn_route.c
index cbaa260873ec..fb87e4730f64 100644
--- a/net/decnet/dn_route.c
+++ b/net/decnet/dn_route.c
@@ -1766,6 +1766,7 @@ out_kfree:
}
static struct file_operations dn_rt_cache_seq_fops = {
+ .owner = THIS_MODULE,
.open = dn_rt_cache_seq_open,
.read = seq_read,
.llseek = seq_lseek,
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index d26810835859..e58581b20e22 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -1313,7 +1313,7 @@ void __init ip_init(void)
ip_rt_init();
inet_initpeers();
-#ifdef CONFIG_IP_MULTICAST
+#if defined(CONFIG_IP_MULTICAST) && defined(CONFIG_PROC_FS)
igmp_mc_proc_init();
#endif
}
diff --git a/net/ipv4/netfilter/ip_conntrack_core.c b/net/ipv4/netfilter/ip_conntrack_core.c
index 0c19a8881a94..b0f1db9c9357 100644
--- a/net/ipv4/netfilter/ip_conntrack_core.c
+++ b/net/ipv4/netfilter/ip_conntrack_core.c
@@ -251,7 +251,7 @@ static void unexpect_related(struct ip_conntrack_expect *expect)
}
/* delete all unconfirmed expectations for this conntrack */
-static void remove_expectations(struct ip_conntrack *ct)
+static void remove_expectations(struct ip_conntrack *ct, int drop_refcount)
{
struct list_head *exp_entry, *next;
struct ip_conntrack_expect *exp;
@@ -266,8 +266,11 @@ static void remove_expectations(struct ip_conntrack *ct)
* the un-established ones only */
if (exp->sibling) {
DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
- /* Indicate that this expectations parent is dead */
- exp->expectant = NULL;
+ if (drop_refcount) {
+ /* Indicate that this expectations parent is dead */
+ ip_conntrack_put(exp->expectant);
+ exp->expectant = NULL;
+ }
continue;
}
@@ -292,7 +295,7 @@ clean_from_lists(struct ip_conntrack *ct)
&ct->tuplehash[IP_CT_DIR_REPLY]);
/* Destroy all un-established, pending expectations */
- remove_expectations(ct);
+ remove_expectations(ct, 1);
}
static void
@@ -1117,7 +1120,7 @@ static inline int unhelp(struct ip_conntrack_tuple_hash *i,
{
if (i->ctrack->helper == me) {
/* Get rid of any expected. */
- remove_expectations(i->ctrack);
+ remove_expectations(i->ctrack, 0);
/* And *then* set helper to NULL */
i->ctrack->helper = NULL;
}
diff --git a/net/ipv4/netfilter/ip_conntrack_irc.c b/net/ipv4/netfilter/ip_conntrack_irc.c
index 79bb3f076b5c..7cb21646e214 100644
--- a/net/ipv4/netfilter/ip_conntrack_irc.c
+++ b/net/ipv4/netfilter/ip_conntrack_irc.c
@@ -54,7 +54,7 @@ MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels");
#endif
static char *dccprotos[] = { "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " };
-#define MAXMATCHLEN 6
+#define MINMATCHLEN 5
DECLARE_LOCK(ip_irc_lock);
struct module *ip_conntrack_irc = THIS_MODULE;
@@ -87,9 +87,11 @@ int parse_dcc(char *data, char *data_end, u_int32_t * ip, u_int16_t * port,
*ip = simple_strtoul(data, &data, 10);
/* skip blanks between ip and port */
- while (*data == ' ')
+ while (*data == ' ') {
+ if (data >= data_end)
+ return -1;
data++;
-
+ }
*port = simple_strtoul(data, &data, 10);
*ad_end_p = data;
@@ -139,13 +141,17 @@ static int help(struct sk_buff *skb,
data = irc_buffer;
data_limit = irc_buffer + skb->len - dataoff;
- while (data < (data_limit - (22 + MAXMATCHLEN))) {
+
+ /* strlen("\1DCC SENT t AAAAAAAA P\1\n")=24
+ * 5+MINMATCHLEN+strlen("t AAAAAAAA P\1\n")=14 */
+ while (data < (data_limit - (19 + MINMATCHLEN))) {
if (memcmp(data, "\1DCC ", 5)) {
data++;
continue;
}
data += 5;
+ /* we have at least (19+MINMATCHLEN)-5 bytes valid data left */
DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n",
NIPQUAD(iph->saddr), ntohs(tcph.source),
@@ -159,6 +165,9 @@ static int help(struct sk_buff *skb,
DEBUGP("DCC %s detected\n", dccprotos[i]);
data += strlen(dccprotos[i]);
+ /* we have at least
+ * (19+MINMATCHLEN)-5-dccprotos[i].matchlen bytes valid
+ * data left (== 14/13 bytes) */
if (parse_dcc((char *)data, data_limit, &dcc_ip,
&dcc_port, &addr_beg_p, &addr_end_p)) {
/* unable to parse */
diff --git a/net/ipv4/netfilter/ipt_MIRROR.c b/net/ipv4/netfilter/ipt_MIRROR.c
index 3f8faff13dc4..1d64fe1cbfe6 100644
--- a/net/ipv4/netfilter/ipt_MIRROR.c
+++ b/net/ipv4/netfilter/ipt_MIRROR.c
@@ -9,6 +9,12 @@
Changes:
25 Aug 2001 Harald Welte <laforge@gnumonks.org>
- decrement and check TTL if not called from FORWARD hook
+ 18 Jul 2003 Harald Welte <laforge@netfilter.org>
+ - merge Patrick McHardy's mirror fixes from 2.4.22 to
+ 2.6.0-test1
+ 19 Jul 2003 Harald Welte <laforge@netfilter.org>
+ - merge Patrick McHardy's rp_filter fixes from 2.4.22 to
+ 2.6.0-test1
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
@@ -32,7 +38,6 @@
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netdevice.h>
#include <linux/route.h>
-struct in_device;
#include <net/route.h>
#if 0
@@ -41,46 +46,58 @@ struct in_device;
#define DEBUGP(format, args...)
#endif
-static int route_mirror(struct sk_buff *skb)
+static inline struct rtable *route_mirror(struct sk_buff *skb, int local)
{
struct iphdr *iph = skb->nh.iph;
- struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->saddr,
- .saddr = iph->daddr,
- .tos = RT_TOS(iph->tos) | RTO_CONN } } };
+ struct dst_entry *odst;
+ struct flowi fl = {};
struct rtable *rt;
- /* Backwards */
- if (ip_route_output_key(&rt, &fl)) {
- return 0;
+ if (local) {
+ fl.nl_u.ip4_u.daddr = iph->saddr;
+ fl.nl_u.ip4_u.saddr = iph->daddr;
+ fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
+
+ if (ip_route_output_key(&rt, &fl) != 0)
+ return NULL;
+ } else {
+ /* non-local src, find valid iif to satisfy
+ * rp-filter when calling ip_route_input(). */
+ fl.nl_u.ip4_u.daddr = iph->daddr;
+ if (ip_route_output_key(&rt, &fl) != 0)
+ return NULL;
+
+ odst = skb->dst;
+ if (ip_route_input(skb, iph->saddr, iph->daddr,
+ RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
+ dst_release(&rt->u.dst);
+ return NULL;
+ }
+ dst_release(&rt->u.dst);
+ rt = (struct rtable *)skb->dst;
+ skb->dst = odst;
}
- /* check if the interface we are leaving by is the same as the
- one we arrived on */
- if (skb->dev == rt->u.dst.dev) {
- /* Drop old route. */
- dst_release(skb->dst);
- skb->dst = &rt->u.dst;
- return 1;
+ if (rt->u.dst.error) {
+ dst_release(&rt->u.dst);
+ rt = NULL;
}
- return 0;
+
+ return rt;
}
-static int ip_rewrite(struct sk_buff **pskb)
+static inline void ip_rewrite(struct sk_buff *skb)
{
u32 odaddr, osaddr;
- if (!skb_ip_make_writable(pskb, sizeof(struct iphdr)))
- return 0;
+ odaddr = skb->nh.iph->saddr;
+ osaddr = skb->nh.iph->daddr;
- odaddr = (*pskb)->nh.iph->saddr;
- osaddr = (*pskb)->nh.iph->daddr;
-
- (*pskb)->nfcache |= NFC_ALTERED;
+ skb->nfcache |= NFC_ALTERED;
/* Rewrite IP header */
- (*pskb)->nh.iph->daddr = odaddr;
- (*pskb)->nh.iph->saddr = osaddr;
- return 1;
+ skb->nh.iph->daddr = odaddr;
+ skb->nh.iph->saddr = osaddr;
}
/* Stolen from ip_finish_output2 */
@@ -113,31 +130,51 @@ static unsigned int ipt_mirror_target(struct sk_buff **pskb,
const void *targinfo,
void *userinfo)
{
- if (((*pskb)->dst != NULL) && route_mirror(*pskb)) {
- if (!ip_rewrite(pskb))
- return NF_DROP;
+ struct rtable *rt;
+ struct sk_buff *nskb;
+ unsigned int hh_len;
- /* If we are not at FORWARD hook (INPUT/PREROUTING),
- * the TTL isn't decreased by the IP stack */
- if (hooknum != NF_IP_FORWARD) {
- if ((*pskb)->nh.iph->ttl <= 1) {
- /* this will traverse normal stack, and
- * thus call conntrack on the icmp packet */
- icmp_send(*pskb, ICMP_TIME_EXCEEDED,
- ICMP_EXC_TTL, 0);
- return NF_DROP;
- }
- /* Made writable by ip_rewrite */
- ip_decrease_ttl((*pskb)->nh.iph);
+ /* Make skb writable */
+ if (!skb_ip_make_writable(pskb, sizeof(struct iphdr)))
+ return 0;
+
+ /* If we are not at FORWARD hook (INPUT/PREROUTING),
+ * the TTL isn't decreased by the IP stack */
+ if (hooknum != NF_IP_FORWARD) {
+ if ((*pskb)->nh.iph->ttl <= 1) {
+ /* this will traverse normal stack, and
+ * thus call conntrack on the icmp packet */
+ icmp_send(*pskb, ICMP_TIME_EXCEEDED,
+ ICMP_EXC_TTL, 0);
+ return NF_DROP;
}
+ ip_decrease_ttl((*pskb)->nh.iph);
+ }
- /* Don't let conntrack code see this packet:
- it will think we are starting a new
- connection! --RR */
- ip_direct_send(*pskb);
+ if ((rt = route_mirror(*pskb, hooknum == NF_IP_LOCAL_IN)) == NULL)
+ return NF_DROP;
- return NF_STOLEN;
+ hh_len = (rt->u.dst.dev->hard_header_len + 15) & ~15;
+
+ /* Copy skb (even if skb is about to be dropped, we can't just
+ * clone it because there may be other things, such as tcpdump,
+ * interested in it). We also need to expand headroom in case
+ * hh_len of incoming interface < hh_len of outgoing interface */
+ nskb = skb_copy_expand(*pskb, hh_len, skb_tailroom(*pskb), GFP_ATOMIC);
+ if (nskb == NULL) {
+ dst_release(&rt->u.dst);
+ return NF_DROP;
}
+
+ dst_release(nskb->dst);
+ nskb->dst = &rt->u.dst;
+
+ ip_rewrite(nskb);
+ /* Don't let conntrack code see this packet:
+ * it will think we are starting a new
+ * connection! --RR */
+ ip_direct_send(nskb);
+
return NF_DROP;
}
diff --git a/net/ipv4/netfilter/ipt_REJECT.c b/net/ipv4/netfilter/ipt_REJECT.c
index 2582a825f499..c1147531acd2 100644
--- a/net/ipv4/netfilter/ipt_REJECT.c
+++ b/net/ipv4/netfilter/ipt_REJECT.c
@@ -1,6 +1,7 @@
/*
* This is a module which is used for rejecting packets.
* Added support for customized reject packets (Jozsef Kadlecsik).
+ * Added support for ICMP type-3-code-13 (Maciej Soltysiak). [RFC 1812]
*/
#include <linux/config.h>
#include <linux/module.h>
@@ -35,134 +36,180 @@ static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct)
}
}
+static inline struct rtable *route_reverse(struct sk_buff *skb, int local)
+{
+ struct iphdr *iph = skb->nh.iph;
+ struct dst_entry *odst;
+ struct flowi fl = {};
+ struct rtable *rt;
+
+ if (local) {
+ fl.nl_u.ip4_u.daddr = iph->saddr;
+ fl.nl_u.ip4_u.saddr = iph->daddr;
+ fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
+
+ if (ip_route_output_key(&rt, &fl) != 0)
+ return NULL;
+ } else {
+ /* non-local src, find valid iif to satisfy
+ * rp-filter when calling ip_route_input. */
+ fl.nl_u.ip4_u.daddr = iph->daddr;
+ if (ip_route_output_key(&rt, &fl) != 0)
+ return NULL;
+
+ odst = skb->dst;
+ if (ip_route_input(skb, iph->saddr, iph->daddr,
+ RT_TOS(iph->tos), rt->u.dst.dev) != 0) {
+ dst_release(&rt->u.dst);
+ return NULL;
+ }
+ dst_release(&rt->u.dst);
+ rt = (struct rtable *)skb->dst;
+ skb->dst = odst;
+ }
+
+ if (rt->u.dst.error) {
+ dst_release(&rt->u.dst);
+ rt = NULL;
+ }
+
+ return rt;
+}
+
/* Send RST reply */
-static unsigned int send_reset(struct sk_buff **pskb, int local)
+static void send_reset(struct sk_buff *oldskb, int local)
{
- struct tcphdr tcph;
+ struct sk_buff *nskb;
+ struct tcphdr *otcph, *tcph;
struct rtable *rt;
+ unsigned int otcplen;
u_int16_t tmp_port;
u_int32_t tmp_addr;
- int needs_ack, hh_len, datalen;
- struct nf_ct_info *oldnfct;
+ int needs_ack;
+ int hh_len;
- /* No RSTs for fragments. */
- if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET))
- return NF_DROP;
+ /* IP header checks: fragment, too short. */
+ if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)
+ || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr))
+ return;
- if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4,
- &tcph, sizeof(tcph)) < 0)
- return NF_DROP;
+ otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl);
+ otcplen = oldskb->len - oldskb->nh.iph->ihl*4;
+
+ if (skb_copy_bits(oldskb, oldskb->nh.iph->ihl*4,
+ otcph, sizeof(*otcph)) < 0)
+ return;
/* No RST for RST. */
- if (tcph.rst)
- return NF_DROP;
+ if (otcph->rst)
+ return;
- /* FIXME: Check checksum. */
- {
- struct flowi fl = { .nl_u = { .ip4_u =
- { .daddr = (*pskb)->nh.iph->saddr,
- .saddr = (local ?
- (*pskb)->nh.iph->daddr :
- 0),
- .tos = RT_TOS((*pskb)->nh.iph->tos) } } };
+ /* Check checksum. */
+ if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr,
+ oldskb->nh.iph->daddr,
+ csum_partial((char *)otcph, otcplen, 0)) != 0)
+ return;
- /* Routing: if not headed for us, route won't like source */
- if (ip_route_output_key(&rt, &fl))
- return NF_DROP;
+ if ((rt = route_reverse(oldskb, local)) == NULL)
+ return;
- hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
- }
+ hh_len = (rt->u.dst.dev->hard_header_len + 15)&~15;
- /* We're going to flip the header around, drop options and data. */
- if (!skb_ip_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(tcph))) {
- ip_rt_put(rt);
- return NF_DROP;
+ /* Copy skb (even if skb is about to be dropped, we can't just
+ clone it because there may be other things, such as tcpdump,
+ interested in it). We also need to expand headroom in case
+ hh_len of incoming interface < hh_len of outgoing interface */
+ nskb = skb_copy_expand(oldskb, hh_len, skb_tailroom(oldskb),
+ GFP_ATOMIC);
+ if (!nskb) {
+ dst_release(&rt->u.dst);
+ return;
}
- (*pskb)->h.th = (void *)(*pskb)->nh.iph + sizeof(tcph);
- datalen = (*pskb)->len - (*pskb)->nh.iph->ihl*4 - tcph.doff*4;
-
- /* Change over route. */
- dst_release((*pskb)->dst);
- (*pskb)->dst = &rt->u.dst;
+ dst_release(nskb->dst);
+ nskb->dst = &rt->u.dst;
/* This packet will not be the same as the other: clear nf fields */
- (*pskb)->nfcache = 0;
+ nf_conntrack_put(nskb->nfct);
+ nskb->nfct = NULL;
+ nskb->nfcache = 0;
#ifdef CONFIG_NETFILTER_DEBUG
- (*pskb)->nf_debug = 0;
+ nskb->nf_debug = 0;
#endif
- (*pskb)->nfmark = 0;
+ nskb->nfmark = 0;
+
+ tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
/* Swap source and dest */
- tmp_addr = (*pskb)->nh.iph->saddr;
- (*pskb)->nh.iph->saddr = (*pskb)->nh.iph->daddr;
- (*pskb)->nh.iph->daddr = tmp_addr;
- tmp_port = (*pskb)->h.th->source;
- (*pskb)->h.th->source = (*pskb)->h.th->dest;
- (*pskb)->h.th->dest = tmp_port;
+ tmp_addr = nskb->nh.iph->saddr;
+ nskb->nh.iph->saddr = nskb->nh.iph->daddr;
+ nskb->nh.iph->daddr = tmp_addr;
+ tmp_port = tcph->source;
+ tcph->source = tcph->dest;
+ tcph->dest = tmp_port;
/* Truncate to length (no data) */
- (*pskb)->h.th->doff = sizeof(struct tcphdr)/4;
- skb_trim(*pskb, (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr));
- (*pskb)->nh.iph->tot_len = htons((*pskb)->len);
+ tcph->doff = sizeof(struct tcphdr)/4;
+ skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
+ nskb->nh.iph->tot_len = htons(nskb->len);
- if ((*pskb)->h.th->ack) {
+ if (tcph->ack) {
needs_ack = 0;
- (*pskb)->h.th->seq = tcph.ack_seq;
- (*pskb)->h.th->ack_seq = 0;
+ tcph->seq = otcph->ack_seq;
+ tcph->ack_seq = 0;
} else {
needs_ack = 1;
- (*pskb)->h.th->ack_seq = htonl(ntohl(tcph.seq)
- + tcph.syn + tcph.fin
- + datalen);
- (*pskb)->h.th->seq = 0;
+ tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin
+ + otcplen - (otcph->doff<<2));
+ tcph->seq = 0;
}
/* Reset flags */
- memset((*pskb)->h.raw + 13, 0, 1);
- (*pskb)->h.th->rst = 1;
- (*pskb)->h.th->ack = needs_ack;
+ ((u_int8_t *)tcph)[13] = 0;
+ tcph->rst = 1;
+ tcph->ack = needs_ack;
- (*pskb)->h.th->window = 0;
- (*pskb)->h.th->urg_ptr = 0;
+ tcph->window = 0;
+ tcph->urg_ptr = 0;
/* Adjust TCP checksum */
- (*pskb)->h.th->check = 0;
- (*pskb)->h.th->check
- = tcp_v4_check((*pskb)->h.th,
- sizeof(struct tcphdr),
- (*pskb)->nh.iph->saddr,
- (*pskb)->nh.iph->daddr,
- csum_partial((*pskb)->h.raw,
- sizeof(struct tcphdr), 0));
+ tcph->check = 0;
+ tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
+ nskb->nh.iph->saddr,
+ nskb->nh.iph->daddr,
+ csum_partial((char *)tcph,
+ sizeof(struct tcphdr), 0));
/* Adjust IP TTL, DF */
- (*pskb)->nh.iph->ttl = MAXTTL;
+ nskb->nh.iph->ttl = MAXTTL;
/* Set DF, id = 0 */
- (*pskb)->nh.iph->frag_off = htons(IP_DF);
- (*pskb)->nh.iph->id = 0;
+ nskb->nh.iph->frag_off = htons(IP_DF);
+ nskb->nh.iph->id = 0;
/* Adjust IP checksum */
- (*pskb)->nh.iph->check = 0;
- (*pskb)->nh.iph->check = ip_fast_csum((*pskb)->nh.raw,
- (*pskb)->nh.iph->ihl);
+ nskb->nh.iph->check = 0;
+ nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph,
+ nskb->nh.iph->ihl);
/* "Never happens" */
- if ((*pskb)->len > dst_pmtu((*pskb)->dst))
- return NF_DROP;
+ if (nskb->len > dst_pmtu(nskb->dst))
+ goto free_nskb;
- /* Related to old connection. */
- oldnfct = (*pskb)->nfct;
- connection_attach(*pskb, oldnfct);
- nf_conntrack_put(oldnfct);
+ connection_attach(nskb, oldskb->nfct);
- NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, *pskb, NULL, (*pskb)->dst->dev,
+ NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
ip_finish_output);
- return NF_STOLEN;
+ return;
+
+ free_nskb:
+ kfree_skb(nskb);
}
-static void send_unreach(const struct sk_buff *skb_in, int code)
+static void send_unreach(struct sk_buff *skb_in, int code)
{
+ struct iphdr *iph;
+ struct udphdr *udph;
+ struct icmphdr *icmph;
struct sk_buff *nskb;
u32 saddr;
u8 tos;
@@ -177,6 +224,8 @@ static void send_unreach(const struct sk_buff *skb_in, int code)
if (!xrlim_allow(&rt->u.dst, 1*HZ))
return;
+ iph = skb_in->nh.iph;
+
/* No replies to physical multicast/broadcast */
if (skb_in->pkt_type!=PACKET_HOST)
return;
@@ -186,38 +235,52 @@ static void send_unreach(const struct sk_buff *skb_in, int code)
return;
/* Only reply to fragment 0. */
- if (skb_in->nh.iph->frag_off&htons(IP_OFFSET))
+ if (iph->frag_off&htons(IP_OFFSET))
return;
/* Ensure we have at least 8 bytes of proto header. */
if (skb_in->len < skb_in->nh.iph->ihl*4 + 8)
return;
+ /* if UDP checksum is set, verify it's correct */
+ if (iph->protocol == IPPROTO_UDP
+ && skb_in->tail-(u8*)iph >= sizeof(struct udphdr)) {
+ int datalen = skb_in->len - (iph->ihl<<2);
+ udph = (struct udphdr *)((char *)iph + (iph->ihl<<2));
+ if (udph->check
+ && csum_tcpudp_magic(iph->saddr, iph->daddr,
+ datalen, IPPROTO_UDP,
+ csum_partial((char *)udph, datalen,
+ 0)) != 0)
+ return;
+ }
+
/* If we send an ICMP error to an ICMP error a mess would result.. */
- if (skb_in->nh.iph->protocol == IPPROTO_ICMP) {
- struct icmphdr icmph;
+ if (iph->protocol == IPPROTO_ICMP
+ && skb_in->tail-(u8*)iph >= sizeof(struct icmphdr)) {
+ icmph = (struct icmphdr *)((char *)iph + (iph->ihl<<2));
if (skb_copy_bits(skb_in, skb_in->nh.iph->ihl*4,
- &icmph, sizeof(icmph)) < 0)
+ icmph, sizeof(*icmph)) < 0)
return;
/* Between echo-reply (0) and timestamp (13),
everything except echo-request (8) is an error.
Also, anything greater than NR_ICMP_TYPES is
unknown, and hence should be treated as an error... */
- if ((icmph.type < ICMP_TIMESTAMP
- && icmph.type != ICMP_ECHOREPLY
- && icmph.type != ICMP_ECHO)
- || icmph.type > NR_ICMP_TYPES)
+ if ((icmph->type < ICMP_TIMESTAMP
+ && icmph->type != ICMP_ECHOREPLY
+ && icmph->type != ICMP_ECHO)
+ || icmph->type > NR_ICMP_TYPES)
return;
}
- saddr = skb_in->nh.iph->daddr;
+ saddr = iph->daddr;
if (!(rt->rt_flags & RTCF_LOCAL))
saddr = 0;
- tos = (skb_in->nh.iph->tos & IPTOS_TOS_MASK)
- | IPTOS_PREC_INTERNETCONTROL;
+ tos = (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL;
+
{
struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = skb_in->nh.iph->saddr,
@@ -247,38 +310,41 @@ static void send_unreach(const struct sk_buff *skb_in, int code)
skb_reserve(nskb, hh_len);
/* Set up IP header */
- nskb->nh.iph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
- nskb->nh.iph->version=4;
- nskb->nh.iph->ihl=5;
- nskb->nh.iph->tos=tos;
- nskb->nh.iph->tot_len = htons(length);
+ iph = nskb->nh.iph
+ = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
+ iph->version=4;
+ iph->ihl=5;
+ iph->tos=tos;
+ iph->tot_len = htons(length);
/* PMTU discovery never applies to ICMP packets. */
- nskb->nh.iph->frag_off = 0;
+ iph->frag_off = 0;
- nskb->nh.iph->ttl = MAXTTL;
- ip_select_ident(nskb->nh.iph, &rt->u.dst, NULL);
- nskb->nh.iph->protocol=IPPROTO_ICMP;
- nskb->nh.iph->saddr=rt->rt_src;
- nskb->nh.iph->daddr=rt->rt_dst;
- nskb->nh.iph->check=0;
- nskb->nh.iph->check = ip_fast_csum(nskb->nh.raw,
- nskb->nh.iph->ihl);
+ iph->ttl = MAXTTL;
+ ip_select_ident(iph, &rt->u.dst, NULL);
+ iph->protocol=IPPROTO_ICMP;
+ iph->saddr=rt->rt_src;
+ iph->daddr=rt->rt_dst;
+ iph->check=0;
+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
/* Set up ICMP header. */
- nskb->h.icmph = (struct icmphdr *)skb_put(nskb,sizeof(struct icmphdr));
- nskb->h.icmph->type = ICMP_DEST_UNREACH;
- nskb->h.icmph->code = code;
- nskb->h.icmph->un.gateway = 0;
- nskb->h.icmph->checksum = 0;
+ icmph = nskb->h.icmph
+ = (struct icmphdr *)skb_put(nskb, sizeof(struct icmphdr));
+ icmph->type = ICMP_DEST_UNREACH;
+ icmph->code = code;
+ icmph->un.gateway = 0;
+ icmph->checksum = 0;
/* Copy as much of original packet as will fit */
data = skb_put(nskb,
length - sizeof(struct iphdr) - sizeof(struct icmphdr));
+
skb_copy_bits(skb_in, 0, data,
length - sizeof(struct iphdr) - sizeof(struct icmphdr));
- nskb->h.icmph->checksum = ip_compute_csum(nskb->h.raw,
- length-sizeof(struct iphdr));
+
+ icmph->checksum = ip_compute_csum((unsigned char *)icmph,
+ length - sizeof(struct iphdr));
connection_attach(nskb, skb_in->nfct);
@@ -322,8 +388,11 @@ static unsigned int reject(struct sk_buff **pskb,
case IPT_ICMP_HOST_PROHIBITED:
send_unreach(*pskb, ICMP_HOST_ANO);
break;
+ case IPT_ICMP_ADMIN_PROHIBITED:
+ send_unreach(*pskb, ICMP_PKT_FILTERED);
+ break;
case IPT_TCP_RESET:
- return send_reset(pskb, hooknum == NF_IP_LOCAL_IN);
+ send_reset(*pskb, hooknum == NF_IP_LOCAL_IN);
case IPT_ICMP_ECHOREPLY:
/* Doesn't happen. */
break;
diff --git a/net/ipv4/netfilter/ipt_helper.c b/net/ipv4/netfilter/ipt_helper.c
index 1f7efb91c5e8..28ab46445e4a 100644
--- a/net/ipv4/netfilter/ipt_helper.c
+++ b/net/ipv4/netfilter/ipt_helper.c
@@ -10,6 +10,7 @@
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/netfilter_ipv4/ip_conntrack.h>
+#include <linux/netfilter_ipv4/ip_conntrack_core.h>
#include <linux/netfilter_ipv4/ip_conntrack_helper.h>
#include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_helper.h>
@@ -34,6 +35,7 @@ match(const struct sk_buff *skb,
struct ip_conntrack_expect *exp;
struct ip_conntrack *ct;
enum ip_conntrack_info ctinfo;
+ int ret = 0;
ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
if (!ct) {
@@ -47,23 +49,27 @@ match(const struct sk_buff *skb,
}
exp = ct->master;
+ READ_LOCK(&ip_conntrack_lock);
if (!exp->expectant) {
DEBUGP("ipt_helper: expectation %p without expectant !?!\n",
exp);
- return 0;
+ goto out_unlock;
}
if (!exp->expectant->helper) {
DEBUGP("ipt_helper: master ct %p has no helper\n",
exp->expectant);
- return 0;
+ goto out_unlock;
}
DEBUGP("master's name = %s , info->name = %s\n",
exp->expectant->helper->name, info->name);
- return !strncmp(exp->expectant->helper->name, info->name,
- strlen(exp->expectant->helper->name)) ^ info->invert;
+ ret = !strncmp(exp->expectant->helper->name, info->name,
+ strlen(exp->expectant->helper->name)) ^ info->invert;
+out_unlock:
+ READ_UNLOCK(&ip_conntrack_lock);
+ return ret;
}
static int check(const char *tablename,
diff --git a/net/ipv6/addrconf.c b/net/ipv6/addrconf.c
index 649df9f76068..925effb2390c 100644
--- a/net/ipv6/addrconf.c
+++ b/net/ipv6/addrconf.c
@@ -130,7 +130,7 @@ static spinlock_t addrconf_verify_lock = SPIN_LOCK_UNLOCKED;
static int addrconf_ifdown(struct net_device *dev, int how);
-static void addrconf_dad_start(struct inet6_ifaddr *ifp);
+static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags);
static void addrconf_dad_timer(unsigned long data);
static void addrconf_dad_completed(struct inet6_ifaddr *ifp);
static void addrconf_rs_timer(unsigned long data);
@@ -710,7 +710,7 @@ retry:
ift->prefered_lft = tmp_prefered_lft;
ift->tstamp = ifp->tstamp;
spin_unlock_bh(&ift->lock);
- addrconf_dad_start(ift);
+ addrconf_dad_start(ift, 0);
in6_ifa_put(ift);
in6_dev_put(idev);
out:
@@ -1247,7 +1247,7 @@ static void addrconf_add_mroute(struct net_device *dev)
rtmsg.rtmsg_dst_len = 8;
rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
rtmsg.rtmsg_ifindex = dev->ifindex;
- rtmsg.rtmsg_flags = RTF_UP|RTF_ADDRCONF;
+ rtmsg.rtmsg_flags = RTF_UP;
rtmsg.rtmsg_type = RTMSG_NEWROUTE;
ip6_route_add(&rtmsg, NULL, NULL);
}
@@ -1274,7 +1274,7 @@ static void addrconf_add_lroute(struct net_device *dev)
struct in6_addr addr;
ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0);
- addrconf_prefix_route(&addr, 64, dev, 0, RTF_ADDRCONF);
+ addrconf_prefix_route(&addr, 64, dev, 0, 0);
}
static struct inet6_dev *addrconf_add_dev(struct net_device *dev)
@@ -1367,7 +1367,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
}
} else if (valid_lft) {
addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len,
- dev, rt_expires, RTF_ADDRCONF|RTF_EXPIRES);
+ dev, rt_expires, RTF_ADDRCONF|RTF_EXPIRES|RTF_PREFIX_RT);
}
if (rt)
dst_release(&rt->u.dst);
@@ -1413,7 +1413,7 @@ ok:
}
update_lft = create = 1;
- addrconf_dad_start(ifp);
+ addrconf_dad_start(ifp, RTF_ADDRCONF|RTF_PREFIX_RT);
}
if (ifp) {
@@ -1586,7 +1586,7 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen)
ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT);
if (!IS_ERR(ifp)) {
- addrconf_dad_start(ifp);
+ addrconf_dad_start(ifp, 0);
in6_ifa_put(ifp);
return 0;
}
@@ -1761,7 +1761,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr
ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT);
if (!IS_ERR(ifp)) {
- addrconf_dad_start(ifp);
+ addrconf_dad_start(ifp, 0);
in6_ifa_put(ifp);
}
}
@@ -2021,8 +2021,7 @@ static void addrconf_rs_timer(unsigned long data)
memset(&rtmsg, 0, sizeof(struct in6_rtmsg));
rtmsg.rtmsg_type = RTMSG_NEWROUTE;
rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
- rtmsg.rtmsg_flags = (RTF_ALLONLINK | RTF_ADDRCONF |
- RTF_DEFAULT | RTF_UP);
+ rtmsg.rtmsg_flags = (RTF_ALLONLINK | RTF_DEFAULT | RTF_UP);
rtmsg.rtmsg_ifindex = ifp->idev->dev->ifindex;
@@ -2036,7 +2035,7 @@ out:
/*
* Duplicate Address Detection
*/
-static void addrconf_dad_start(struct inet6_ifaddr *ifp)
+static void addrconf_dad_start(struct inet6_ifaddr *ifp, int flags)
{
struct net_device *dev;
unsigned long rand_num;
@@ -2046,7 +2045,8 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp)
addrconf_join_solict(dev, &ifp->addr);
if (ifp->prefix_len != 128 && (ifp->flags&IFA_F_PERMANENT))
- addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, 0, RTF_ADDRCONF);
+ addrconf_prefix_route(&ifp->addr, ifp->prefix_len, dev, 0,
+ flags);
net_srandom(ifp->addr.s6_addr32[3]);
rand_num = net_random() % (ifp->idev->cnf.rtr_solicit_delay ? : 1);
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 69d7791712f8..b3adf22ef02e 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -1459,13 +1459,20 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
struct in6_addr *src,
int iif,
int type, u32 pid, u32 seq,
- struct nlmsghdr *in_nlh)
+ struct nlmsghdr *in_nlh, int prefix)
{
struct rtmsg *rtm;
struct nlmsghdr *nlh;
unsigned char *b = skb->tail;
struct rta_cacheinfo ci;
+ if (prefix) { /* user wants prefix routes only */
+ if (!(rt->rt6i_flags & RTF_PREFIX_RT)) {
+ /* success since this is not a prefix route */
+ return 1;
+ }
+ }
+
if (!pid && in_nlh) {
pid = in_nlh->nlmsg_pid;
}
@@ -1546,10 +1553,17 @@ rtattr_failure:
static int rt6_dump_route(struct rt6_info *rt, void *p_arg)
{
struct rt6_rtnl_dump_arg *arg = (struct rt6_rtnl_dump_arg *) p_arg;
+ struct rtmsg *rtm;
+ int prefix;
+
+ rtm = NLMSG_DATA(arg->cb->nlh);
+ if (rtm)
+ prefix = (rtm->rtm_flags & RTM_F_PREFIX) != 0;
+ else prefix = 0;
return rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq,
- NULL);
+ NULL, prefix);
}
static int fib6_dump_node(struct fib6_walker_t *w)
@@ -1697,7 +1711,7 @@ int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
&fl.fl6_dst, &fl.fl6_src,
iif,
RTM_NEWROUTE, NETLINK_CB(in_skb).pid,
- nlh->nlmsg_seq, nlh);
+ nlh->nlmsg_seq, nlh, 0);
if (err < 0) {
err = -EMSGSIZE;
goto out_free;
@@ -1723,7 +1737,7 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nlmsghdr *nlh)
netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, ENOBUFS);
return;
}
- if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, 0, 0, nlh) < 0) {
+ if (rt6_fill_node(skb, rt, NULL, NULL, 0, event, 0, 0, nlh, 0) < 0) {
kfree_skb(skb);
netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, EINVAL);
return;