Commit 54cdf53b authored by David S. Miller's avatar David S. Miller

Merge davem@nuts.ninka.net:/home/davem/src/BK/net-2.5

into kernel.bkbits.net:/home/davem/net-2.5
parents 22dc9664 3c00a346
...@@ -1632,8 +1632,8 @@ L: linux-scsi@vger.kernel.org ...@@ -1632,8 +1632,8 @@ L: linux-scsi@vger.kernel.org
S: Maintained S: Maintained
SCTP PROTOCOL SCTP PROTOCOL
P: Jon Grimm P: Sridhar Samudrala
M: jgrimm2@us.ibm.com M: sri@us.ibm.com
L: lksctp-developers@lists.sourceforge.net L: lksctp-developers@lists.sourceforge.net
S: Supported S: Supported
......
...@@ -148,6 +148,8 @@ static struct pci_device_id tg3_pci_tbl[] __devinitdata = { ...@@ -148,6 +148,8 @@ static struct pci_device_id tg3_pci_tbl[] __devinitdata = {
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000, { PCI_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC1000,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, 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_VENDOR_ID_ALTIMA, PCI_DEVICE_ID_ALTIMA_AC9100,
PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL }, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0UL },
{ 0, } { 0, }
......
...@@ -5832,6 +5832,7 @@ ...@@ -5832,6 +5832,7 @@
1737 Linksys 1737 Linksys
173b Altima (nee Broadcom) 173b Altima (nee Broadcom)
03e8 AC1000 Gigabit Ethernet 03e8 AC1000 Gigabit Ethernet
03e9 AC1001 Gigabit Ethernet
03ea AC9100 Gigabit Ethernet 03ea AC9100 Gigabit Ethernet
1743 Peppercon AG 1743 Peppercon AG
8139 ROL/F-100 Fast Ethernet Adapter with ROL 8139 ROL/F-100 Fast Ethernet Adapter with ROL
......
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
#define RTF_DEFAULT 0x00010000 /* default - learned via ND */ #define RTF_DEFAULT 0x00010000 /* default - learned via ND */
#define RTF_ALLONLINK 0x00020000 /* fallback, no routers on link */ #define RTF_ALLONLINK 0x00020000 /* fallback, no routers on link */
#define RTF_ADDRCONF 0x00040000 /* addrconf route - RA */ #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_NONEXTHOP 0x00200000 /* route with no nexthop */
#define RTF_EXPIRES 0x00400000 #define RTF_EXPIRES 0x00400000
......
...@@ -33,6 +33,23 @@ struct ebt_counter ...@@ -33,6 +33,23 @@ struct ebt_counter
uint64_t bcnt; 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 { struct ebt_entries {
/* this field is always set to zero /* this field is always set to zero
* See EBT_ENTRY_OR_ENTRIES. * See EBT_ENTRY_OR_ENTRIES.
...@@ -47,7 +64,7 @@ struct ebt_entries { ...@@ -47,7 +64,7 @@ struct ebt_entries {
/* nr. of entries */ /* nr. of entries */
unsigned int nentries; unsigned int nentries;
/* entry list */ /* entry list */
char data[0]; char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
}; };
/* used for the bitmask of struct ebt_entry */ /* used for the bitmask of struct ebt_entry */
...@@ -87,7 +104,7 @@ struct ebt_entry_match ...@@ -87,7 +104,7 @@ struct ebt_entry_match
} u; } u;
/* size of data */ /* size of data */
unsigned int match_size; unsigned int match_size;
unsigned char data[0]; unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
}; };
struct ebt_entry_watcher struct ebt_entry_watcher
...@@ -98,7 +115,7 @@ struct ebt_entry_watcher ...@@ -98,7 +115,7 @@ struct ebt_entry_watcher
} u; } u;
/* size of data */ /* size of data */
unsigned int watcher_size; unsigned int watcher_size;
unsigned char data[0]; unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
}; };
struct ebt_entry_target struct ebt_entry_target
...@@ -109,7 +126,7 @@ struct ebt_entry_target ...@@ -109,7 +126,7 @@ struct ebt_entry_target
} u; } u;
/* size of data */ /* size of data */
unsigned int target_size; unsigned int target_size;
unsigned char data[0]; unsigned char data[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
}; };
#define EBT_STANDARD_TARGET "standard" #define EBT_STANDARD_TARGET "standard"
...@@ -143,24 +160,7 @@ struct ebt_entry { ...@@ -143,24 +160,7 @@ struct ebt_entry {
unsigned int target_offset; unsigned int target_offset;
/* sizeof ebt_entry + matches + watchers + target */ /* sizeof ebt_entry + matches + watchers + target */
unsigned int next_offset; unsigned int next_offset;
unsigned char elems[0]; unsigned char elems[0] __attribute__ ((aligned (__alignof__(struct ebt_replace))));
};
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;
}; };
/* {g,s}etsockopt numbers */ /* {g,s}etsockopt numbers */
...@@ -263,6 +263,8 @@ struct ebt_table ...@@ -263,6 +263,8 @@ struct ebt_table
struct module *me; 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 int ebt_register_table(struct ebt_table *table);
extern void ebt_unregister_table(struct ebt_table *table); extern void ebt_unregister_table(struct ebt_table *table);
extern int ebt_register_match(struct ebt_match *match); extern int ebt_register_match(struct ebt_match *match);
......
...@@ -9,7 +9,8 @@ enum ipt_reject_with { ...@@ -9,7 +9,8 @@ enum ipt_reject_with {
IPT_ICMP_ECHOREPLY, IPT_ICMP_ECHOREPLY,
IPT_ICMP_NET_PROHIBITED, IPT_ICMP_NET_PROHIBITED,
IPT_ICMP_HOST_PROHIBITED, IPT_ICMP_HOST_PROHIBITED,
IPT_TCP_RESET IPT_TCP_RESET,
IPT_ICMP_ADMIN_PROHIBITED
}; };
struct ipt_reject_info { struct ipt_reject_info {
......
...@@ -1757,6 +1757,7 @@ ...@@ -1757,6 +1757,7 @@
#define PCI_VENDOR_ID_ALTIMA 0x173b #define PCI_VENDOR_ID_ALTIMA 0x173b
#define PCI_DEVICE_ID_ALTIMA_AC1000 0x03e8 #define PCI_DEVICE_ID_ALTIMA_AC1000 0x03e8
#define PCI_DEVICE_ID_ALTIMA_AC1001 0x03e9
#define PCI_DEVICE_ID_ALTIMA_AC9100 0x03ea #define PCI_DEVICE_ID_ALTIMA_AC9100 0x03ea
#define PCI_VENDOR_ID_SYMPHONY 0x1c1c #define PCI_VENDOR_ID_SYMPHONY 0x1c1c
......
...@@ -168,6 +168,7 @@ enum rt_scope_t ...@@ -168,6 +168,7 @@ enum rt_scope_t
#define RTM_F_NOTIFY 0x100 /* Notify user of route change */ #define RTM_F_NOTIFY 0x100 /* Notify user of route change */
#define RTM_F_CLONED 0x200 /* This route is cloned */ #define RTM_F_CLONED 0x200 /* This route is cloned */
#define RTM_F_EQUALIZE 0x400 /* Multipath equalizer: NI */ #define RTM_F_EQUALIZE 0x400 /* Multipath equalizer: NI */
#define RTM_F_PREFIX 0x800 /* Prefix addresses */
/* Reserved table identifiers */ /* Reserved table identifiers */
...@@ -458,6 +459,40 @@ struct ifinfomsg ...@@ -458,6 +459,40 @@ struct ifinfomsg
unsigned ifi_change; /* IFF_* change mask */ 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 enum
{ {
IFLA_UNSPEC, IFLA_UNSPEC,
...@@ -599,6 +634,22 @@ extern void __rta_fill(struct sk_buff *skb, int attrtype, int attrlen, const voi ...@@ -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; \ ({ if (skb_tailroom(skb) < (int)RTA_SPACE(attrlen)) goto rtattr_failure; \
__rta_fill(skb, attrtype, attrlen, data); }) __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 void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change);
extern struct semaphore rtnl_sem; extern struct semaphore rtnl_sem;
......
...@@ -1031,7 +1031,7 @@ static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr, ...@@ -1031,7 +1031,7 @@ static void lane2_associate_ind (struct net_device *dev, u8 *mac_addr,
#define LEC_ARP_REFRESH_INTERVAL (3*HZ) #define LEC_ARP_REFRESH_INTERVAL (3*HZ)
static void lec_arp_check_expire(unsigned long data); 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); void dump_arp_table(struct lec_priv *priv);
/* /*
...@@ -1371,7 +1371,7 @@ lec_arp_destroy(struct lec_priv *priv) ...@@ -1371,7 +1371,7 @@ lec_arp_destroy(struct lec_priv *priv)
struct lec_arp_table *entry, *next; struct lec_arp_table *entry, *next;
int i; int i;
del_timer(&priv->lec_arp_timer); del_timer_sync(&priv->lec_arp_timer);
/* /*
* Remove all entries * Remove all entries
...@@ -1386,7 +1386,7 @@ lec_arp_destroy(struct lec_priv *priv) ...@@ -1386,7 +1386,7 @@ lec_arp_destroy(struct lec_priv *priv)
entry = priv->lec_arp_empty_ones; entry = priv->lec_arp_empty_ones;
while(entry) { while(entry) {
next = entry->next; next = entry->next;
del_timer(&entry->timer); del_timer_sync(&entry->timer);
lec_arp_clear_vccs(entry); lec_arp_clear_vccs(entry);
kfree(entry); kfree(entry);
entry = next; entry = next;
...@@ -1395,7 +1395,7 @@ lec_arp_destroy(struct lec_priv *priv) ...@@ -1395,7 +1395,7 @@ lec_arp_destroy(struct lec_priv *priv)
entry = priv->lec_no_forward; entry = priv->lec_no_forward;
while(entry) { while(entry) {
next = entry->next; next = entry->next;
del_timer(&entry->timer); del_timer_sync(&entry->timer);
lec_arp_clear_vccs(entry); lec_arp_clear_vccs(entry);
kfree(entry); kfree(entry);
entry = next; entry = next;
...@@ -1404,7 +1404,7 @@ lec_arp_destroy(struct lec_priv *priv) ...@@ -1404,7 +1404,7 @@ lec_arp_destroy(struct lec_priv *priv)
entry = priv->mcast_fwds; entry = priv->mcast_fwds;
while(entry) { while(entry) {
next = entry->next; next = entry->next;
del_timer(&entry->timer); /* No timer, LANEv2 7.1.20 and 2.3.5.3 */
lec_arp_clear_vccs(entry); lec_arp_clear_vccs(entry);
kfree(entry); kfree(entry);
entry = next; entry = next;
...@@ -1478,8 +1478,6 @@ lec_arp_expire_arp(unsigned long data) ...@@ -1478,8 +1478,6 @@ lec_arp_expire_arp(unsigned long data)
entry = (struct lec_arp_table *)data; entry = (struct lec_arp_table *)data;
del_timer(&entry->timer);
DPRINTK("lec_arp_expire_arp\n"); DPRINTK("lec_arp_expire_arp\n");
if (entry->status == ESI_ARP_PENDING) { if (entry->status == ESI_ARP_PENDING) {
if (entry->no_tries <= entry->priv->max_retry_count) { if (entry->no_tries <= entry->priv->max_retry_count) {
...@@ -1489,8 +1487,7 @@ lec_arp_expire_arp(unsigned long data) ...@@ -1489,8 +1487,7 @@ lec_arp_expire_arp(unsigned long data)
send_to_lecd(entry->priv, l_arp_xmt, entry->mac_addr, NULL, NULL); send_to_lecd(entry->priv, l_arp_xmt, entry->mac_addr, NULL, NULL);
entry->no_tries++; entry->no_tries++;
} }
entry->timer.expires = jiffies + (1*HZ); mod_timer(&entry->timer, jiffies + (1*HZ));
add_timer(&entry->timer);
} }
} }
...@@ -1562,8 +1559,6 @@ lec_arp_check_expire(unsigned long data) ...@@ -1562,8 +1559,6 @@ lec_arp_check_expire(unsigned long data)
unsigned long time_to_check; unsigned long time_to_check;
int i; int i;
del_timer(&priv->lec_arp_timer);
DPRINTK("lec_arp_check_expire %p,%d\n",priv, DPRINTK("lec_arp_check_expire %p,%d\n",priv,
atomic_read(&priv->lec_arp_users)); atomic_read(&priv->lec_arp_users));
DPRINTK("expire: eo:%p nf:%p\n",priv->lec_arp_empty_ones, DPRINTK("expire: eo:%p nf:%p\n",priv->lec_arp_empty_ones,
...@@ -1621,8 +1616,8 @@ lec_arp_check_expire(unsigned long data) ...@@ -1621,8 +1616,8 @@ lec_arp_check_expire(unsigned long data)
} }
lec_arp_put(priv); 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. * Try to find vcc where mac_address is attached.
......
...@@ -110,23 +110,38 @@ static int br_dev_accept_fastpath(struct net_device *dev, struct dst_entry *dst) ...@@ -110,23 +110,38 @@ static int br_dev_accept_fastpath(struct net_device *dev, struct dst_entry *dst)
return -1; 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) void br_dev_setup(struct net_device *dev)
{ {
memset(dev->dev_addr, 0, ETH_ALEN); memset(dev->dev_addr, 0, ETH_ALEN);
ether_setup(dev);
dev->do_ioctl = br_dev_do_ioctl; dev->do_ioctl = br_dev_do_ioctl;
dev->get_stats = br_dev_get_stats; dev->get_stats = br_dev_get_stats;
dev->hard_start_xmit = br_dev_xmit; dev->hard_start_xmit = br_dev_xmit;
dev->open = br_dev_open; dev->open = br_dev_open;
dev->set_multicast_list = br_dev_set_multicast_list; 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); SET_MODULE_OWNER(dev);
dev->stop = br_dev_stop; dev->stop = br_dev_stop;
dev->accept_fastpath = br_dev_accept_fastpath; dev->accept_fastpath = br_dev_accept_fastpath;
dev->tx_queue_len = 0; dev->tx_queue_len = 0;
dev->set_mac_address = NULL; dev->set_mac_address = NULL;
dev->priv_flags = IFF_EBRIDGE; dev->priv_flags = IFF_EBRIDGE;
ether_setup(dev);
} }
...@@ -41,6 +41,13 @@ static int br_initial_port_cost(struct net_device *dev) ...@@ -41,6 +41,13 @@ static int br_initial_port_cost(struct net_device *dev)
static void destroy_nbp(void *arg) static void destroy_nbp(void *arg)
{ {
struct net_bridge_port *p = 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); dev_put(p->dev);
kfree(p); kfree(p);
} }
...@@ -53,16 +60,19 @@ static void del_nbp(struct net_bridge_port *p) ...@@ -53,16 +60,19 @@ static void del_nbp(struct net_bridge_port *p)
br_stp_disable_port(p); br_stp_disable_port(p);
dev_set_promiscuity(dev, -1); dev_set_promiscuity(dev, -1);
dev->br_port = NULL;
list_del_rcu(&p->list); list_del_rcu(&p->list);
br_fdb_delete_by_port(p->br, p); 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); 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; struct list_head *p, *n;
...@@ -71,6 +81,10 @@ static void del_ifs(struct net_bridge *br) ...@@ -71,6 +81,10 @@ static void del_ifs(struct net_bridge *br)
del_nbp(list_entry(p, struct net_bridge_port, list)); del_nbp(list_entry(p, struct net_bridge_port, list));
} }
spin_unlock_bh(&br->lock); spin_unlock_bh(&br->lock);
del_timer_sync(&br->gc_timer);
unregister_netdevice(br->dev);
} }
static struct net_bridge *new_nb(const char *name) static struct net_bridge *new_nb(const char *name)
...@@ -182,15 +196,14 @@ int br_del_bridge(const char *name) ...@@ -182,15 +196,14 @@ int br_del_bridge(const char *name)
ret = -EBUSY; ret = -EBUSY;
} }
else { else
del_ifs((struct net_bridge *) dev->priv); del_br(dev->priv);
unregister_netdevice(dev);
}
rtnl_unlock(); rtnl_unlock();
return ret; return ret;
} }
/* called under bridge lock */
int br_add_if(struct net_bridge *br, struct net_device *dev) int br_add_if(struct net_bridge *br, struct net_device *dev)
{ {
struct net_bridge_port *p; struct net_bridge_port *p;
...@@ -205,7 +218,6 @@ int br_add_if(struct net_bridge *br, struct net_device *dev) ...@@ -205,7 +218,6 @@ int br_add_if(struct net_bridge *br, struct net_device *dev)
return -ELOOP; return -ELOOP;
dev_hold(dev); dev_hold(dev);
spin_lock_bh(&br->lock);
if ((p = new_nbp(br, dev)) == NULL) { if ((p = new_nbp(br, dev)) == NULL) {
spin_unlock_bh(&br->lock); spin_unlock_bh(&br->lock);
dev_put(dev); dev_put(dev);
...@@ -218,26 +230,21 @@ int br_add_if(struct net_bridge *br, struct net_device *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); br_fdb_insert(br, p, dev->dev_addr, 1);
if ((br->dev->flags & IFF_UP) && (dev->flags & IFF_UP)) if ((br->dev->flags & IFF_UP) && (dev->flags & IFF_UP))
br_stp_enable_port(p); br_stp_enable_port(p);
spin_unlock_bh(&br->lock);
return 0; return 0;
} }
/* called under bridge lock */
int br_del_if(struct net_bridge *br, struct net_device *dev) int br_del_if(struct net_bridge *br, struct net_device *dev)
{ {
struct net_bridge_port *p; struct net_bridge_port *p;
int retval = 0;
spin_lock_bh(&br->lock);
if ((p = dev->br_port) == NULL || p->br != br) if ((p = dev->br_port) == NULL || p->br != br)
retval = -EINVAL; return -EINVAL;
else {
del_nbp(p);
br_stp_recalculate_bridge_id(br);
}
spin_unlock_bh(&br->lock);
return retval; del_nbp(p);
br_stp_recalculate_bridge_id(br);
return 0;
} }
int br_get_bridge_ifindices(int *indices, int num) int br_get_bridge_ifindices(int *indices, int num)
...@@ -274,13 +281,8 @@ void __exit br_cleanup_bridges(void) ...@@ -274,13 +281,8 @@ void __exit br_cleanup_bridges(void)
rtnl_lock(); rtnl_lock();
for (dev = dev_base; dev; dev = nxt) { for (dev = dev_base; dev; dev = nxt) {
nxt = dev->next; nxt = dev->next;
if (dev->priv_flags & IFF_EBRIDGE) { if (dev->priv_flags & IFF_EBRIDGE)
pr_debug("cleanup %s\n", dev->name); del_br(dev->priv);
del_ifs((struct net_bridge *) dev->priv);
unregister_netdevice(dev);
}
} }
rtnl_unlock(); rtnl_unlock();
......
...@@ -59,10 +59,12 @@ static int br_ioctl_device(struct net_bridge *br, ...@@ -59,10 +59,12 @@ static int br_ioctl_device(struct net_bridge *br,
if (dev == NULL) if (dev == NULL)
return -EINVAL; return -EINVAL;
spin_lock_bh(&br->lock);
if (cmd == BRCTL_ADD_IF) if (cmd == BRCTL_ADD_IF)
ret = br_add_if(br, dev); ret = br_add_if(br, dev);
else else
ret = br_del_if(br, dev); ret = br_del_if(br, dev);
spin_unlock_bh(&br->lock);
dev_put(dev); dev_put(dev);
return ret; return ret;
......
...@@ -38,39 +38,27 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v ...@@ -38,39 +38,27 @@ static int br_device_event(struct notifier_block *unused, unsigned long event, v
br = p->br; br = p->br;
spin_lock_bh(&br->lock);
switch (event) switch (event)
{ {
case NETDEV_CHANGEADDR: case NETDEV_CHANGEADDR:
spin_lock_bh(&br->lock);
br_fdb_changeaddr(p, dev->dev_addr); br_fdb_changeaddr(p, dev->dev_addr);
br_stp_recalculate_bridge_id(br); 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; break;
case NETDEV_DOWN: case NETDEV_DOWN:
if (br->dev->flags & IFF_UP) { br_stp_disable_port(p);
spin_lock_bh(&br->lock);
br_stp_disable_port(p);
spin_unlock_bh(&br->lock);
}
break; break;
case NETDEV_UP: case NETDEV_UP:
if (!(br->dev->flags & IFF_UP)) { br_stp_enable_port(p);
spin_lock_bh(&br->lock);
br_stp_enable_port(p);
spin_unlock_bh(&br->lock);
}
break; break;
case NETDEV_UNREGISTER: case NETDEV_UNREGISTER:
br_del_if(br, dev); br_del_if(br, dev);
break; break;
} }
spin_unlock_bh(&br->lock);
return NOTIFY_DONE; return NOTIFY_DONE;
} }
...@@ -20,7 +20,11 @@ ...@@ -20,7 +20,11 @@
#include "br_private_stp.h" #include "br_private_stp.h"
static const char *br_port_state_names[] = { 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) 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) ...@@ -289,22 +293,20 @@ static inline void br_topology_change_acknowledged(struct net_bridge *br)
/* called under bridge lock */ /* called under bridge lock */
void br_topology_change_detection(struct net_bridge *br) void br_topology_change_detection(struct net_bridge *br)
{ {
if (!(br->dev->flags & IFF_UP)) int isroot = br_is_root_bridge(br);
return;
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 (isroot) {
if (br_is_root_bridge(br)) {
printk(", propagating");
br->topology_change = 1; br->topology_change = 1;
mod_timer(&br->topology_change_timer, jiffies mod_timer(&br->topology_change_timer, jiffies
+ br->bridge_forward_delay + br->bridge_max_age); + br->bridge_forward_delay + br->bridge_max_age);
} else if (!br->topology_change_detected) { } else if (!br->topology_change_detected) {
printk(", sending tcn bpdu");
br_transmit_tcn(br); br_transmit_tcn(br);
mod_timer(&br->tcn_timer, jiffies + br->bridge_hello_time); mod_timer(&br->tcn_timer, jiffies + br->bridge_hello_time);
} }
printk("\n");
br->topology_change_detected = 1; br->topology_change_detected = 1;
} }
......
...@@ -43,8 +43,7 @@ void br_stp_enable_bridge(struct net_bridge *br) ...@@ -43,8 +43,7 @@ void br_stp_enable_bridge(struct net_bridge *br)
struct net_bridge_port *p; struct net_bridge_port *p;
spin_lock_bh(&br->lock); spin_lock_bh(&br->lock);
br->hello_timer.expires = jiffies + br->hello_time; mod_timer(&br->hello_timer, jiffies + br->hello_time);
add_timer(&br->hello_timer);
br_config_bpdu_generation(br); br_config_bpdu_generation(br);
list_for_each_entry(p, &br->port_list, list) { list_for_each_entry(p, &br->port_list, list) {
...@@ -74,8 +73,6 @@ void br_stp_disable_bridge(struct net_bridge *br) ...@@ -74,8 +73,6 @@ void br_stp_disable_bridge(struct net_bridge *br)
del_timer_sync(&br->hello_timer); del_timer_sync(&br->hello_timer);
del_timer_sync(&br->topology_change_timer); del_timer_sync(&br->topology_change_timer);
del_timer_sync(&br->tcn_timer); del_timer_sync(&br->tcn_timer);
del_timer_sync(&br->gc_timer);
} }
/* called under bridge lock */ /* called under bridge lock */
......
...@@ -43,8 +43,7 @@ static void br_hello_timer_expired(unsigned long arg) ...@@ -43,8 +43,7 @@ static void br_hello_timer_expired(unsigned long arg)
if (br->dev->flags & IFF_UP) { if (br->dev->flags & IFF_UP) {
br_config_bpdu_generation(br); br_config_bpdu_generation(br);
br->hello_timer.expires = jiffies + br->hello_time; mod_timer(&br->hello_timer, jiffies + br->hello_time);
add_timer(&br->hello_timer);
} }
spin_unlock_bh(&br->lock); spin_unlock_bh(&br->lock);
} }
...@@ -73,6 +72,8 @@ static void br_message_age_timer_expired(unsigned long arg) ...@@ -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. * check is redundant. I'm leaving it in for now, though.
*/ */
spin_lock_bh(&br->lock); spin_lock_bh(&br->lock);
if (p->state == BR_STATE_DISABLED)
goto unlock;
was_root = br_is_root_bridge(br); was_root = br_is_root_bridge(br);
br_become_designated_port(p); br_become_designated_port(p);
...@@ -80,6 +81,7 @@ static void br_message_age_timer_expired(unsigned long arg) ...@@ -80,6 +81,7 @@ static void br_message_age_timer_expired(unsigned long arg)
br_port_state_selection(br); br_port_state_selection(br);
if (br_is_root_bridge(br) && !was_root) if (br_is_root_bridge(br) && !was_root)
br_become_root_bridge(br); br_become_root_bridge(br);
unlock:
spin_unlock_bh(&br->lock); spin_unlock_bh(&br->lock);
} }
...@@ -93,8 +95,8 @@ static void br_forward_delay_timer_expired(unsigned long arg) ...@@ -93,8 +95,8 @@ static void br_forward_delay_timer_expired(unsigned long arg)
spin_lock_bh(&br->lock); spin_lock_bh(&br->lock);
if (p->state == BR_STATE_LISTENING) { if (p->state == BR_STATE_LISTENING) {
p->state = BR_STATE_LEARNING; p->state = BR_STATE_LEARNING;
p->forward_delay_timer.expires = jiffies + br->forward_delay; mod_timer(&p->forward_delay_timer,
add_timer(&p->forward_delay_timer); jiffies + br->forward_delay);
} else if (p->state == BR_STATE_LEARNING) { } else if (p->state == BR_STATE_LEARNING) {
p->state = BR_STATE_FORWARDING; p->state = BR_STATE_FORWARDING;
if (br_is_designated_for_some_port(br)) if (br_is_designated_for_some_port(br))
...@@ -113,8 +115,7 @@ static void br_tcn_timer_expired(unsigned long arg) ...@@ -113,8 +115,7 @@ static void br_tcn_timer_expired(unsigned long arg)
if (br->dev->flags & IFF_UP) { if (br->dev->flags & IFF_UP) {
br_transmit_tcn(br); br_transmit_tcn(br);
br->tcn_timer.expires = jiffies + br->bridge_hello_time; mod_timer(&br->tcn_timer,jiffies + br->bridge_hello_time);
add_timer(&br->tcn_timer);
} }
spin_unlock_bh(&br->lock); spin_unlock_bh(&br->lock);
} }
......
...@@ -99,7 +99,7 @@ static int ebt_arp_check(const char *tablename, unsigned int hookmask, ...@@ -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; 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; return -EINVAL;
if ((e->ethproto != __constant_htons(ETH_P_ARP) && if ((e->ethproto != __constant_htons(ETH_P_ARP) &&
e->ethproto != __constant_htons(ETH_P_RARP)) || e->ethproto != __constant_htons(ETH_P_RARP)) ||
......
...@@ -47,7 +47,7 @@ static int ebt_target_dnat_check(const char *tablename, unsigned int hookmask, ...@@ -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)))) && (hookmask & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_OUT)))) &&
(strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) ) (strcmp(tablename, "broute") || hookmask & ~(1 << NF_BR_BROUTING)) )
return -EINVAL; return -EINVAL;
if (datalen != sizeof(struct ebt_nat_info)) if (datalen != EBT_ALIGN(sizeof(struct ebt_nat_info)))
return -EINVAL; return -EINVAL;
if (INVALID_TARGET) if (INVALID_TARGET)
return -EINVAL; return -EINVAL;
......
...@@ -75,7 +75,7 @@ static int ebt_ip_check(const char *tablename, unsigned int hookmask, ...@@ -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; 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; return -EINVAL;
if (e->ethproto != __constant_htons(ETH_P_IP) || if (e->ethproto != __constant_htons(ETH_P_IP) ||
e->invflags & EBT_IPROTO) e->invflags & EBT_IPROTO)
......
...@@ -22,7 +22,7 @@ static int ebt_log_check(const char *tablename, unsigned int hookmask, ...@@ -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; 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; return -EINVAL;
if (info->bitmask & ~EBT_LOG_MASK) if (info->bitmask & ~EBT_LOG_MASK)
return -EINVAL; return -EINVAL;
......
...@@ -35,7 +35,7 @@ static int ebt_target_mark_check(const char *tablename, unsigned int hookmask, ...@@ -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; 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; return -EINVAL;
if (BASE_CHAIN && info->target == EBT_RETURN) if (BASE_CHAIN && info->target == EBT_RETURN)
return -EINVAL; return -EINVAL;
......
...@@ -28,7 +28,7 @@ static int ebt_mark_check(const char *tablename, unsigned int hookmask, ...@@ -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; 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; return -EINVAL;
if (info->bitmask & ~EBT_MARK_MASK) if (info->bitmask & ~EBT_MARK_MASK)
return -EINVAL; return -EINVAL;
......
...@@ -28,7 +28,7 @@ static int ebt_pkttype_check(const char *tablename, unsigned int hookmask, ...@@ -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; 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; return -EINVAL;
if (info->invert != 0 && info->invert != 1) if (info->invert != 0 && info->invert != 1)
return -EINVAL; return -EINVAL;
......
...@@ -47,7 +47,7 @@ static int ebt_target_redirect_check(const char *tablename, unsigned int hookmas ...@@ -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; 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; return -EINVAL;
if (BASE_CHAIN && info->target == EBT_RETURN) if (BASE_CHAIN && info->target == EBT_RETURN)
return -EINVAL; return -EINVAL;
......
...@@ -40,7 +40,7 @@ static int ebt_target_snat_check(const char *tablename, unsigned int hookmask, ...@@ -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; 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; return -EINVAL;
if (BASE_CHAIN && info->target == EBT_RETURN) if (BASE_CHAIN && info->target == EBT_RETURN)
return -EINVAL; return -EINVAL;
......
...@@ -150,7 +150,7 @@ static int ebt_stp_check(const char *tablename, unsigned int hookmask, ...@@ -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) const struct ebt_entry *e, void *data, unsigned int datalen)
{ {
struct ebt_stp_info *info = (struct ebt_stp_info *)data; 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 bridge_ula[6] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
uint8_t msk[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; uint8_t msk[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
......
...@@ -35,7 +35,7 @@ MODULE_DESCRIPTION("802.1Q match module (ebtables extension), v" ...@@ -35,7 +35,7 @@ MODULE_DESCRIPTION("802.1Q match module (ebtables extension), v"
MODULE_LICENSE("GPL"); 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 INV_FLAG(_inv_flag_) (info->invflags & _inv_flag_) ? "!" : ""
#define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_ #define GET_BITMASK(_BIT_MASK_) info->bitmask & _BIT_MASK_
#define SET_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, ...@@ -94,7 +94,7 @@ ebt_check_vlan(const char *tablename,
struct ebt_vlan_info *info = (struct ebt_vlan_info *) data; struct ebt_vlan_info *info = (struct ebt_vlan_info *) data;
/* Parameters buffer overflow check */ /* Parameters buffer overflow check */
if (datalen != sizeof(struct ebt_vlan_info)) { if (datalen != EBT_ALIGN(sizeof(struct ebt_vlan_info))) {
DEBUG_MSG DEBUG_MSG
("passed size %d is not eq to ebt_vlan_info (%Zd)\n", ("passed size %d is not eq to ebt_vlan_info (%Zd)\n",
datalen, sizeof(struct ebt_vlan_info)); datalen, sizeof(struct ebt_vlan_info));
......
...@@ -256,10 +256,9 @@ int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen) ...@@ -256,10 +256,9 @@ int sk_run_filter(struct sk_buff *skb, struct sock_filter *filter, int flen)
k = X + fentry->k; k = X + fentry->k;
goto load_b; goto load_b;
case BPF_LDX|BPF_B|BPF_MSH: case BPF_LDX|BPF_B|BPF_MSH:
k = fentry->k; if (fentry->k >= len)
if (k >= 0 && (unsigned int)k >= len)
return 0; return 0;
X = (data[k] & 0xf) << 2; X = (data[fentry->k] & 0xf) << 2;
continue; continue;
case BPF_LD|BPF_IMM: case BPF_LD|BPF_IMM:
A = fentry->k; A = fentry->k;
......
...@@ -186,7 +186,7 @@ struct netstat_fs_entry { ...@@ -186,7 +186,7 @@ struct netstat_fs_entry {
static ssize_t net_device_stat_show(unsigned long var, char *buf) 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 */ /* generate a read-only statistics attribute */
......
...@@ -625,66 +625,62 @@ int ip_route_me_harder(struct sk_buff **pskb) ...@@ -625,66 +625,62 @@ int ip_route_me_harder(struct sk_buff **pskb)
{ {
struct iphdr *iph = (*pskb)->nh.iph; struct iphdr *iph = (*pskb)->nh.iph;
struct rtable *rt; struct rtable *rt;
struct flowi fl = { .nl_u = { .ip4_u = struct flowi fl = {};
{ .daddr = iph->daddr, struct dst_entry *odst;
.saddr = iph->saddr, unsigned int hh_len;
.tos = RT_TOS(iph->tos)|RTO_CONN,
#ifdef CONFIG_IP_ROUTE_FWMARK /* some non-standard hacks like ipt_REJECT.c:send_reset() can cause
.fwmark = (*pskb)->nfmark * packets with foreign saddr to appear on the NF_IP_LOCAL_OUT hook.
#endif */
} }, if (inet_addr_type(iph->saddr) == RTN_LOCAL) {
.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0, fl.nl_u.ip4_u.daddr = iph->daddr;
}; fl.nl_u.ip4_u.saddr = iph->saddr;
struct net_device *dev_src = NULL; fl.nl_u.ip4_u.tos = RT_TOS(iph->tos);
int err; fl.oif = (*pskb)->sk ? (*pskb)->sk->sk_bound_dev_if : 0;
/* 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,
#ifdef CONFIG_IP_ROUTE_FWMARK #ifdef CONFIG_IP_ROUTE_FWMARK
(*pskb)->nfmark, fl.nl_u.ip4_u.fwmark = (*pskb)->nfmark;
#else
0UL,
#endif #endif
err); if (ip_route_output_key(&rt, &fl) != 0)
goto out; return -1;
}
/* Drop old route. */ /* Drop old route. */
dst_release((*pskb)->dst); dst_release((*pskb)->dst);
(*pskb)->dst = &rt->u.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. */ /* 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; struct sk_buff *nskb;
nskb = skb_realloc_headroom(*pskb, nskb = skb_realloc_headroom(*pskb, hh_len);
(*pskb)->dst->dev->hard_header_len); if (!nskb)
if (!nskb) { return -1;
err = -ENOMEM;
goto out;
}
if ((*pskb)->sk) if ((*pskb)->sk)
skb_set_owner_w(nskb, (*pskb)->sk); skb_set_owner_w(nskb, (*pskb)->sk);
kfree_skb(*pskb); kfree_skb(*pskb);
*pskb = nskb; *pskb = nskb;
} }
out: return 0;
if (dev_src)
dev_put(dev_src);
return err;
} }
int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len) int skb_ip_make_writable(struct sk_buff **pskb, unsigned int writable_len)
......
...@@ -47,6 +47,9 @@ ...@@ -47,6 +47,9 @@
* Also moved to /proc/net/pktgen/ * Also moved to /proc/net/pktgen/
* --ro * --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. * See Documentation/networking/pktgen.txt for how to use this.
*/ */
...@@ -85,9 +88,9 @@ ...@@ -85,9 +88,9 @@
#define cycles() ((u32)get_cycles()) #define cycles() ((u32)get_cycles())
#define VERSION "pktgen version 1.2" #define VERSION "pktgen version 1.3"
static char version[] __initdata = 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 */ /* Used to help with determining the pkts on receive */
...@@ -611,12 +614,11 @@ static void inject(struct pktgen_info* info) ...@@ -611,12 +614,11 @@ static void inject(struct pktgen_info* info)
kfree_skb(skb); kfree_skb(skb);
skb = fill_packet(odev, info); skb = fill_packet(odev, info);
if (skb == NULL) { if (skb == NULL) {
break; goto out_reldev;
} }
fp++; fp++;
fp_tmp = 0; /* reset counter */ fp_tmp = 0; /* reset counter */
} }
atomic_inc(&skb->users);
} }
nr_frags = skb_shinfo(skb)->nr_frags; nr_frags = skb_shinfo(skb)->nr_frags;
...@@ -624,7 +626,11 @@ static void inject(struct pktgen_info* info) ...@@ -624,7 +626,11 @@ static void inject(struct pktgen_info* info)
spin_lock_bh(&odev->xmit_lock); spin_lock_bh(&odev->xmit_lock);
if (!netif_queue_stopped(odev)) { if (!netif_queue_stopped(odev)) {
atomic_inc(&skb->users);
if (odev->hard_start_xmit(skb, odev)) { if (odev->hard_start_xmit(skb, odev)) {
atomic_dec(&skb->users);
if (net_ratelimit()) { if (net_ratelimit()) {
printk(KERN_INFO "Hard xmit error\n"); printk(KERN_INFO "Hard xmit error\n");
} }
...@@ -729,15 +735,15 @@ static void inject(struct pktgen_info* info) ...@@ -729,15 +735,15 @@ static void inject(struct pktgen_info* info)
(unsigned long long) info->errors (unsigned long long) info->errors
); );
} }
kfree_skb(skb);
out_reldev: out_reldev:
if (odev) { if (odev) {
dev_put(odev); dev_put(odev);
odev = NULL; odev = NULL;
} }
/* TODO: Is this worth printing out (other than for debug?) */
printk("fp = %llu\n", (unsigned long long) fp);
return; return;
} }
...@@ -953,7 +959,8 @@ static int proc_write(struct file *file, const char *user_buffer, ...@@ -953,7 +959,8 @@ static int proc_write(struct file *file, const char *user_buffer,
if (len < 0) if (len < 0)
return len; return len;
memset(name, 0, sizeof(name)); 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; i += len;
max = count -i; max = count -i;
...@@ -1083,18 +1090,20 @@ static int proc_write(struct file *file, const char *user_buffer, ...@@ -1083,18 +1090,20 @@ static int proc_write(struct file *file, const char *user_buffer,
if (len < 0) if (len < 0)
return len; return len;
memset(info->outdev, 0, sizeof(info->outdev)); 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; i += len;
sprintf(result, "OK: odev=%s", info->outdev); sprintf(result, "OK: odev=%s", info->outdev);
return count; return count;
} }
if (!strcmp(name, "flag")) { if (!strcmp(name, "flag")) {
char f[32]; char f[32];
memset(f, 0, 32);
len = strn_len(&user_buffer[i], sizeof(f) - 1); len = strn_len(&user_buffer[i], sizeof(f) - 1);
if (len < 0) if (len < 0)
return len; 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; i += len;
if (strcmp(f, "IPSRC_RND") == 0) { if (strcmp(f, "IPSRC_RND") == 0) {
info->flags |= F_IPSRC_RND; info->flags |= F_IPSRC_RND;
...@@ -1146,7 +1155,8 @@ static int proc_write(struct file *file, const char *user_buffer, ...@@ -1146,7 +1155,8 @@ static int proc_write(struct file *file, const char *user_buffer,
if (len < 0) if (len < 0)
return len; return len;
memset(info->dst_min, 0, sizeof(info->dst_min)); 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) if(debug)
printk("pg: dst_min set to: %s\n", info->dst_min); printk("pg: dst_min set to: %s\n", info->dst_min);
i += len; i += len;
...@@ -1158,7 +1168,8 @@ static int proc_write(struct file *file, const char *user_buffer, ...@@ -1158,7 +1168,8 @@ static int proc_write(struct file *file, const char *user_buffer,
if (len < 0) if (len < 0)
return len; return len;
memset(info->dst_max, 0, sizeof(info->dst_max)); 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) if(debug)
printk("pg: dst_max set to: %s\n", info->dst_max); printk("pg: dst_max set to: %s\n", info->dst_max);
i += len; i += len;
...@@ -1170,7 +1181,8 @@ static int proc_write(struct file *file, const char *user_buffer, ...@@ -1170,7 +1181,8 @@ static int proc_write(struct file *file, const char *user_buffer,
if (len < 0) if (len < 0)
return len; return len;
memset(info->src_min, 0, sizeof(info->src_min)); 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) if(debug)
printk("pg: src_min set to: %s\n", info->src_min); printk("pg: src_min set to: %s\n", info->src_min);
i += len; i += len;
...@@ -1182,7 +1194,8 @@ static int proc_write(struct file *file, const char *user_buffer, ...@@ -1182,7 +1194,8 @@ static int proc_write(struct file *file, const char *user_buffer,
if (len < 0) if (len < 0)
return len; return len;
memset(info->src_max, 0, sizeof(info->src_max)); 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) if(debug)
printk("pg: src_max set to: %s\n", info->src_max); printk("pg: src_max set to: %s\n", info->src_max);
i += len; i += len;
...@@ -1197,7 +1210,8 @@ static int proc_write(struct file *file, const char *user_buffer, ...@@ -1197,7 +1210,8 @@ static int proc_write(struct file *file, const char *user_buffer,
if (len < 0) if (len < 0)
return len; return len;
memset(valstr, 0, sizeof(valstr)); 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; i += len;
for(*m = 0;*v && m < info->dst_mac + 6; v++) { 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, ...@@ -1229,7 +1243,8 @@ static int proc_write(struct file *file, const char *user_buffer,
if (len < 0) if (len < 0)
return len; return len;
memset(valstr, 0, sizeof(valstr)); 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; i += len;
for(*m = 0;*v && m < info->src_mac + 6; v++) { for(*m = 0;*v && m < info->src_mac + 6; v++) {
......
...@@ -191,9 +191,18 @@ static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev, ...@@ -191,9 +191,18 @@ static int rtnetlink_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
if (dev->master) if (dev->master)
RTA_PUT(skb, IFLA_MASTER, sizeof(int), &dev->master->ifindex); RTA_PUT(skb, IFLA_MASTER, sizeof(int), &dev->master->ifindex);
if (dev->get_stats) { if (dev->get_stats) {
struct net_device_stats *stats = dev->get_stats(dev); unsigned long *stats = (unsigned long*)dev->get_stats(dev);
if (stats) if (stats) {
RTA_PUT(skb, IFLA_STATS, sizeof(*stats), 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; nlh->nlmsg_len = skb->tail - b;
return skb->len; return skb->len;
......
...@@ -86,7 +86,7 @@ ctl_table core_table[] = { ...@@ -86,7 +86,7 @@ ctl_table core_table[] = {
{ {
.ctl_name = NET_CORE_NO_CONG_THRESH, .ctl_name = NET_CORE_NO_CONG_THRESH,
.procname = "no_cong_thresh", .procname = "no_cong_thresh",
.data = &no_cong, .data = &no_cong_thresh,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec .proc_handler = &proc_dointvec
......
...@@ -2308,6 +2308,7 @@ static int dn_socket_seq_open(struct inode *inode, struct file *file) ...@@ -2308,6 +2308,7 @@ static int dn_socket_seq_open(struct inode *inode, struct file *file)
} }
static struct file_operations dn_socket_seq_fops = { static struct file_operations dn_socket_seq_fops = {
.owner = THIS_MODULE,
.open = dn_socket_seq_open, .open = dn_socket_seq_open,
.read = seq_read, .read = seq_read,
.llseek = seq_lseek, .llseek = seq_lseek,
......
...@@ -1443,6 +1443,7 @@ static int dn_dev_seq_open(struct inode *inode, struct file *file) ...@@ -1443,6 +1443,7 @@ static int dn_dev_seq_open(struct inode *inode, struct file *file)
} }
static struct file_operations dn_dev_seq_fops = { static struct file_operations dn_dev_seq_fops = {
.owner = THIS_MODULE,
.open = dn_dev_seq_open, .open = dn_dev_seq_open,
.read = seq_read, .read = seq_read,
.llseek = seq_lseek, .llseek = seq_lseek,
......
...@@ -1766,6 +1766,7 @@ static int dn_rt_cache_seq_open(struct inode *inode, struct file *file) ...@@ -1766,6 +1766,7 @@ static int dn_rt_cache_seq_open(struct inode *inode, struct file *file)
} }
static struct file_operations dn_rt_cache_seq_fops = { static struct file_operations dn_rt_cache_seq_fops = {
.owner = THIS_MODULE,
.open = dn_rt_cache_seq_open, .open = dn_rt_cache_seq_open,
.read = seq_read, .read = seq_read,
.llseek = seq_lseek, .llseek = seq_lseek,
......
...@@ -1313,7 +1313,7 @@ void __init ip_init(void) ...@@ -1313,7 +1313,7 @@ void __init ip_init(void)
ip_rt_init(); ip_rt_init();
inet_initpeers(); inet_initpeers();
#ifdef CONFIG_IP_MULTICAST #if defined(CONFIG_IP_MULTICAST) && defined(CONFIG_PROC_FS)
igmp_mc_proc_init(); igmp_mc_proc_init();
#endif #endif
} }
...@@ -251,7 +251,7 @@ static void unexpect_related(struct ip_conntrack_expect *expect) ...@@ -251,7 +251,7 @@ static void unexpect_related(struct ip_conntrack_expect *expect)
} }
/* delete all unconfirmed expectations for this conntrack */ /* 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 list_head *exp_entry, *next;
struct ip_conntrack_expect *exp; struct ip_conntrack_expect *exp;
...@@ -266,8 +266,11 @@ static void remove_expectations(struct ip_conntrack *ct) ...@@ -266,8 +266,11 @@ static void remove_expectations(struct ip_conntrack *ct)
* the un-established ones only */ * the un-established ones only */
if (exp->sibling) { if (exp->sibling) {
DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct); DEBUGP("remove_expectations: skipping established %p of %p\n", exp->sibling, ct);
/* Indicate that this expectations parent is dead */ if (drop_refcount) {
exp->expectant = NULL; /* Indicate that this expectations parent is dead */
ip_conntrack_put(exp->expectant);
exp->expectant = NULL;
}
continue; continue;
} }
...@@ -292,7 +295,7 @@ clean_from_lists(struct ip_conntrack *ct) ...@@ -292,7 +295,7 @@ clean_from_lists(struct ip_conntrack *ct)
&ct->tuplehash[IP_CT_DIR_REPLY]); &ct->tuplehash[IP_CT_DIR_REPLY]);
/* Destroy all un-established, pending expectations */ /* Destroy all un-established, pending expectations */
remove_expectations(ct); remove_expectations(ct, 1);
} }
static void static void
...@@ -1117,7 +1120,7 @@ static inline int unhelp(struct ip_conntrack_tuple_hash *i, ...@@ -1117,7 +1120,7 @@ static inline int unhelp(struct ip_conntrack_tuple_hash *i,
{ {
if (i->ctrack->helper == me) { if (i->ctrack->helper == me) {
/* Get rid of any expected. */ /* Get rid of any expected. */
remove_expectations(i->ctrack); remove_expectations(i->ctrack, 0);
/* And *then* set helper to NULL */ /* And *then* set helper to NULL */
i->ctrack->helper = NULL; i->ctrack->helper = NULL;
} }
......
...@@ -54,7 +54,7 @@ MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels"); ...@@ -54,7 +54,7 @@ MODULE_PARM_DESC(dcc_timeout, "timeout on for unestablished DCC channels");
#endif #endif
static char *dccprotos[] = { "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " }; static char *dccprotos[] = { "SEND ", "CHAT ", "MOVE ", "TSEND ", "SCHAT " };
#define MAXMATCHLEN 6 #define MINMATCHLEN 5
DECLARE_LOCK(ip_irc_lock); DECLARE_LOCK(ip_irc_lock);
struct module *ip_conntrack_irc = THIS_MODULE; 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, ...@@ -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); *ip = simple_strtoul(data, &data, 10);
/* skip blanks between ip and port */ /* skip blanks between ip and port */
while (*data == ' ') while (*data == ' ') {
if (data >= data_end)
return -1;
data++; data++;
}
*port = simple_strtoul(data, &data, 10); *port = simple_strtoul(data, &data, 10);
*ad_end_p = data; *ad_end_p = data;
...@@ -139,13 +141,17 @@ static int help(struct sk_buff *skb, ...@@ -139,13 +141,17 @@ static int help(struct sk_buff *skb,
data = irc_buffer; data = irc_buffer;
data_limit = irc_buffer + skb->len - dataoff; 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)) { if (memcmp(data, "\1DCC ", 5)) {
data++; data++;
continue; continue;
} }
data += 5; 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", DEBUGP("DCC found in master %u.%u.%u.%u:%u %u.%u.%u.%u:%u...\n",
NIPQUAD(iph->saddr), ntohs(tcph.source), NIPQUAD(iph->saddr), ntohs(tcph.source),
...@@ -159,6 +165,9 @@ static int help(struct sk_buff *skb, ...@@ -159,6 +165,9 @@ static int help(struct sk_buff *skb,
DEBUGP("DCC %s detected\n", dccprotos[i]); DEBUGP("DCC %s detected\n", dccprotos[i]);
data += strlen(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, if (parse_dcc((char *)data, data_limit, &dcc_ip,
&dcc_port, &addr_beg_p, &addr_end_p)) { &dcc_port, &addr_beg_p, &addr_end_p)) {
/* unable to parse */ /* unable to parse */
......
...@@ -9,6 +9,12 @@ ...@@ -9,6 +9,12 @@
Changes: Changes:
25 Aug 2001 Harald Welte <laforge@gnumonks.org> 25 Aug 2001 Harald Welte <laforge@gnumonks.org>
- decrement and check TTL if not called from FORWARD hook - 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 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 under the terms of the GNU General Public License as published by the
...@@ -32,7 +38,6 @@ ...@@ -32,7 +38,6 @@
#include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/route.h> #include <linux/route.h>
struct in_device;
#include <net/route.h> #include <net/route.h>
#if 0 #if 0
...@@ -41,46 +46,58 @@ struct in_device; ...@@ -41,46 +46,58 @@ struct in_device;
#define DEBUGP(format, args...) #define DEBUGP(format, args...)
#endif #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 iphdr *iph = skb->nh.iph;
struct flowi fl = { .nl_u = { .ip4_u = { .daddr = iph->saddr, struct dst_entry *odst;
.saddr = iph->daddr, struct flowi fl = {};
.tos = RT_TOS(iph->tos) | RTO_CONN } } };
struct rtable *rt; struct rtable *rt;
/* Backwards */ if (local) {
if (ip_route_output_key(&rt, &fl)) { fl.nl_u.ip4_u.daddr = iph->saddr;
return 0; 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 if (rt->u.dst.error) {
one we arrived on */ dst_release(&rt->u.dst);
if (skb->dev == rt->u.dst.dev) { rt = NULL;
/* Drop old route. */
dst_release(skb->dst);
skb->dst = &rt->u.dst;
return 1;
} }
return 0;
return rt;
} }
static int ip_rewrite(struct sk_buff **pskb) static inline void ip_rewrite(struct sk_buff *skb)
{ {
u32 odaddr, osaddr; u32 odaddr, osaddr;
if (!skb_ip_make_writable(pskb, sizeof(struct iphdr))) odaddr = skb->nh.iph->saddr;
return 0; osaddr = skb->nh.iph->daddr;
odaddr = (*pskb)->nh.iph->saddr; skb->nfcache |= NFC_ALTERED;
osaddr = (*pskb)->nh.iph->daddr;
(*pskb)->nfcache |= NFC_ALTERED;
/* Rewrite IP header */ /* Rewrite IP header */
(*pskb)->nh.iph->daddr = odaddr; skb->nh.iph->daddr = odaddr;
(*pskb)->nh.iph->saddr = osaddr; skb->nh.iph->saddr = osaddr;
return 1;
} }
/* Stolen from ip_finish_output2 */ /* Stolen from ip_finish_output2 */
...@@ -113,31 +130,51 @@ static unsigned int ipt_mirror_target(struct sk_buff **pskb, ...@@ -113,31 +130,51 @@ static unsigned int ipt_mirror_target(struct sk_buff **pskb,
const void *targinfo, const void *targinfo,
void *userinfo) void *userinfo)
{ {
if (((*pskb)->dst != NULL) && route_mirror(*pskb)) { struct rtable *rt;
if (!ip_rewrite(pskb)) struct sk_buff *nskb;
return NF_DROP; unsigned int hh_len;
/* If we are not at FORWARD hook (INPUT/PREROUTING), /* Make skb writable */
* the TTL isn't decreased by the IP stack */ if (!skb_ip_make_writable(pskb, sizeof(struct iphdr)))
if (hooknum != NF_IP_FORWARD) { return 0;
if ((*pskb)->nh.iph->ttl <= 1) {
/* this will traverse normal stack, and /* If we are not at FORWARD hook (INPUT/PREROUTING),
* thus call conntrack on the icmp packet */ * the TTL isn't decreased by the IP stack */
icmp_send(*pskb, ICMP_TIME_EXCEEDED, if (hooknum != NF_IP_FORWARD) {
ICMP_EXC_TTL, 0); if ((*pskb)->nh.iph->ttl <= 1) {
return NF_DROP; /* this will traverse normal stack, and
} * thus call conntrack on the icmp packet */
/* Made writable by ip_rewrite */ icmp_send(*pskb, ICMP_TIME_EXCEEDED,
ip_decrease_ttl((*pskb)->nh.iph); ICMP_EXC_TTL, 0);
return NF_DROP;
} }
ip_decrease_ttl((*pskb)->nh.iph);
}
/* Don't let conntrack code see this packet: if ((rt = route_mirror(*pskb, hooknum == NF_IP_LOCAL_IN)) == NULL)
it will think we are starting a new return NF_DROP;
connection! --RR */
ip_direct_send(*pskb);
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; return NF_DROP;
} }
......
/* /*
* This is a module which is used for rejecting packets. * This is a module which is used for rejecting packets.
* Added support for customized reject packets (Jozsef Kadlecsik). * 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/config.h>
#include <linux/module.h> #include <linux/module.h>
...@@ -35,134 +36,180 @@ static void connection_attach(struct sk_buff *new_skb, struct nf_ct_info *nfct) ...@@ -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 */ /* 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; struct rtable *rt;
unsigned int otcplen;
u_int16_t tmp_port; u_int16_t tmp_port;
u_int32_t tmp_addr; u_int32_t tmp_addr;
int needs_ack, hh_len, datalen; int needs_ack;
struct nf_ct_info *oldnfct; int hh_len;
/* No RSTs for fragments. */ /* IP header checks: fragment, too short. */
if ((*pskb)->nh.iph->frag_off & htons(IP_OFFSET)) if (oldskb->nh.iph->frag_off & htons(IP_OFFSET)
return NF_DROP; || oldskb->len < (oldskb->nh.iph->ihl<<2) + sizeof(struct tcphdr))
return;
if (skb_copy_bits(*pskb, (*pskb)->nh.iph->ihl*4, otcph = (struct tcphdr *)((u_int32_t*)oldskb->nh.iph + oldskb->nh.iph->ihl);
&tcph, sizeof(tcph)) < 0) otcplen = oldskb->len - oldskb->nh.iph->ihl*4;
return NF_DROP;
if (skb_copy_bits(oldskb, oldskb->nh.iph->ihl*4,
otcph, sizeof(*otcph)) < 0)
return;
/* No RST for RST. */ /* No RST for RST. */
if (tcph.rst) if (otcph->rst)
return NF_DROP; return;
/* FIXME: Check checksum. */ /* Check checksum. */
{ if (tcp_v4_check(otcph, otcplen, oldskb->nh.iph->saddr,
struct flowi fl = { .nl_u = { .ip4_u = oldskb->nh.iph->daddr,
{ .daddr = (*pskb)->nh.iph->saddr, csum_partial((char *)otcph, otcplen, 0)) != 0)
.saddr = (local ? return;
(*pskb)->nh.iph->daddr :
0),
.tos = RT_TOS((*pskb)->nh.iph->tos) } } };
/* Routing: if not headed for us, route won't like source */ if ((rt = route_reverse(oldskb, local)) == NULL)
if (ip_route_output_key(&rt, &fl)) return;
return NF_DROP;
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. */ /* Copy skb (even if skb is about to be dropped, we can't just
if (!skb_ip_make_writable(pskb, (*pskb)->nh.iph->ihl*4+sizeof(tcph))) { clone it because there may be other things, such as tcpdump,
ip_rt_put(rt); interested in it). We also need to expand headroom in case
return NF_DROP; 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); dst_release(nskb->dst);
datalen = (*pskb)->len - (*pskb)->nh.iph->ihl*4 - tcph.doff*4; nskb->dst = &rt->u.dst;
/* Change over route. */
dst_release((*pskb)->dst);
(*pskb)->dst = &rt->u.dst;
/* This packet will not be the same as the other: clear nf fields */ /* 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 #ifdef CONFIG_NETFILTER_DEBUG
(*pskb)->nf_debug = 0; nskb->nf_debug = 0;
#endif #endif
(*pskb)->nfmark = 0; nskb->nfmark = 0;
tcph = (struct tcphdr *)((u_int32_t*)nskb->nh.iph + nskb->nh.iph->ihl);
/* Swap source and dest */ /* Swap source and dest */
tmp_addr = (*pskb)->nh.iph->saddr; tmp_addr = nskb->nh.iph->saddr;
(*pskb)->nh.iph->saddr = (*pskb)->nh.iph->daddr; nskb->nh.iph->saddr = nskb->nh.iph->daddr;
(*pskb)->nh.iph->daddr = tmp_addr; nskb->nh.iph->daddr = tmp_addr;
tmp_port = (*pskb)->h.th->source; tmp_port = tcph->source;
(*pskb)->h.th->source = (*pskb)->h.th->dest; tcph->source = tcph->dest;
(*pskb)->h.th->dest = tmp_port; tcph->dest = tmp_port;
/* Truncate to length (no data) */ /* Truncate to length (no data) */
(*pskb)->h.th->doff = sizeof(struct tcphdr)/4; tcph->doff = sizeof(struct tcphdr)/4;
skb_trim(*pskb, (*pskb)->nh.iph->ihl*4 + sizeof(struct tcphdr)); skb_trim(nskb, nskb->nh.iph->ihl*4 + sizeof(struct tcphdr));
(*pskb)->nh.iph->tot_len = htons((*pskb)->len); nskb->nh.iph->tot_len = htons(nskb->len);
if ((*pskb)->h.th->ack) { if (tcph->ack) {
needs_ack = 0; needs_ack = 0;
(*pskb)->h.th->seq = tcph.ack_seq; tcph->seq = otcph->ack_seq;
(*pskb)->h.th->ack_seq = 0; tcph->ack_seq = 0;
} else { } else {
needs_ack = 1; needs_ack = 1;
(*pskb)->h.th->ack_seq = htonl(ntohl(tcph.seq) tcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn + otcph->fin
+ tcph.syn + tcph.fin + otcplen - (otcph->doff<<2));
+ datalen); tcph->seq = 0;
(*pskb)->h.th->seq = 0;
} }
/* Reset flags */ /* Reset flags */
memset((*pskb)->h.raw + 13, 0, 1); ((u_int8_t *)tcph)[13] = 0;
(*pskb)->h.th->rst = 1; tcph->rst = 1;
(*pskb)->h.th->ack = needs_ack; tcph->ack = needs_ack;
(*pskb)->h.th->window = 0; tcph->window = 0;
(*pskb)->h.th->urg_ptr = 0; tcph->urg_ptr = 0;
/* Adjust TCP checksum */ /* Adjust TCP checksum */
(*pskb)->h.th->check = 0; tcph->check = 0;
(*pskb)->h.th->check tcph->check = tcp_v4_check(tcph, sizeof(struct tcphdr),
= tcp_v4_check((*pskb)->h.th, nskb->nh.iph->saddr,
sizeof(struct tcphdr), nskb->nh.iph->daddr,
(*pskb)->nh.iph->saddr, csum_partial((char *)tcph,
(*pskb)->nh.iph->daddr, sizeof(struct tcphdr), 0));
csum_partial((*pskb)->h.raw,
sizeof(struct tcphdr), 0));
/* Adjust IP TTL, DF */ /* Adjust IP TTL, DF */
(*pskb)->nh.iph->ttl = MAXTTL; nskb->nh.iph->ttl = MAXTTL;
/* Set DF, id = 0 */ /* Set DF, id = 0 */
(*pskb)->nh.iph->frag_off = htons(IP_DF); nskb->nh.iph->frag_off = htons(IP_DF);
(*pskb)->nh.iph->id = 0; nskb->nh.iph->id = 0;
/* Adjust IP checksum */ /* Adjust IP checksum */
(*pskb)->nh.iph->check = 0; nskb->nh.iph->check = 0;
(*pskb)->nh.iph->check = ip_fast_csum((*pskb)->nh.raw, nskb->nh.iph->check = ip_fast_csum((unsigned char *)nskb->nh.iph,
(*pskb)->nh.iph->ihl); nskb->nh.iph->ihl);
/* "Never happens" */ /* "Never happens" */
if ((*pskb)->len > dst_pmtu((*pskb)->dst)) if (nskb->len > dst_pmtu(nskb->dst))
return NF_DROP; goto free_nskb;
/* Related to old connection. */ connection_attach(nskb, oldskb->nfct);
oldnfct = (*pskb)->nfct;
connection_attach(*pskb, oldnfct);
nf_conntrack_put(oldnfct);
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); 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; struct sk_buff *nskb;
u32 saddr; u32 saddr;
u8 tos; u8 tos;
...@@ -177,6 +224,8 @@ static void send_unreach(const struct sk_buff *skb_in, int code) ...@@ -177,6 +224,8 @@ static void send_unreach(const struct sk_buff *skb_in, int code)
if (!xrlim_allow(&rt->u.dst, 1*HZ)) if (!xrlim_allow(&rt->u.dst, 1*HZ))
return; return;
iph = skb_in->nh.iph;
/* No replies to physical multicast/broadcast */ /* No replies to physical multicast/broadcast */
if (skb_in->pkt_type!=PACKET_HOST) if (skb_in->pkt_type!=PACKET_HOST)
return; return;
...@@ -186,38 +235,52 @@ static void send_unreach(const struct sk_buff *skb_in, int code) ...@@ -186,38 +235,52 @@ static void send_unreach(const struct sk_buff *skb_in, int code)
return; return;
/* Only reply to fragment 0. */ /* Only reply to fragment 0. */
if (skb_in->nh.iph->frag_off&htons(IP_OFFSET)) if (iph->frag_off&htons(IP_OFFSET))
return; return;
/* Ensure we have at least 8 bytes of proto header. */ /* Ensure we have at least 8 bytes of proto header. */
if (skb_in->len < skb_in->nh.iph->ihl*4 + 8) if (skb_in->len < skb_in->nh.iph->ihl*4 + 8)
return; 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 we send an ICMP error to an ICMP error a mess would result.. */
if (skb_in->nh.iph->protocol == IPPROTO_ICMP) { if (iph->protocol == IPPROTO_ICMP
struct icmphdr icmph; && 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, if (skb_copy_bits(skb_in, skb_in->nh.iph->ihl*4,
&icmph, sizeof(icmph)) < 0) icmph, sizeof(*icmph)) < 0)
return; return;
/* Between echo-reply (0) and timestamp (13), /* Between echo-reply (0) and timestamp (13),
everything except echo-request (8) is an error. everything except echo-request (8) is an error.
Also, anything greater than NR_ICMP_TYPES is Also, anything greater than NR_ICMP_TYPES is
unknown, and hence should be treated as an error... */ unknown, and hence should be treated as an error... */
if ((icmph.type < ICMP_TIMESTAMP if ((icmph->type < ICMP_TIMESTAMP
&& icmph.type != ICMP_ECHOREPLY && icmph->type != ICMP_ECHOREPLY
&& icmph.type != ICMP_ECHO) && icmph->type != ICMP_ECHO)
|| icmph.type > NR_ICMP_TYPES) || icmph->type > NR_ICMP_TYPES)
return; return;
} }
saddr = skb_in->nh.iph->daddr; saddr = iph->daddr;
if (!(rt->rt_flags & RTCF_LOCAL)) if (!(rt->rt_flags & RTCF_LOCAL))
saddr = 0; saddr = 0;
tos = (skb_in->nh.iph->tos & IPTOS_TOS_MASK) tos = (iph->tos & IPTOS_TOS_MASK) | IPTOS_PREC_INTERNETCONTROL;
| IPTOS_PREC_INTERNETCONTROL;
{ {
struct flowi fl = { .nl_u = { .ip4_u = struct flowi fl = { .nl_u = { .ip4_u =
{ .daddr = skb_in->nh.iph->saddr, { .daddr = skb_in->nh.iph->saddr,
...@@ -247,38 +310,41 @@ static void send_unreach(const struct sk_buff *skb_in, int code) ...@@ -247,38 +310,41 @@ static void send_unreach(const struct sk_buff *skb_in, int code)
skb_reserve(nskb, hh_len); skb_reserve(nskb, hh_len);
/* Set up IP header */ /* Set up IP header */
nskb->nh.iph = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr)); iph = nskb->nh.iph
nskb->nh.iph->version=4; = (struct iphdr *)skb_put(nskb, sizeof(struct iphdr));
nskb->nh.iph->ihl=5; iph->version=4;
nskb->nh.iph->tos=tos; iph->ihl=5;
nskb->nh.iph->tot_len = htons(length); iph->tos=tos;
iph->tot_len = htons(length);
/* PMTU discovery never applies to ICMP packets. */ /* PMTU discovery never applies to ICMP packets. */
nskb->nh.iph->frag_off = 0; iph->frag_off = 0;
nskb->nh.iph->ttl = MAXTTL; iph->ttl = MAXTTL;
ip_select_ident(nskb->nh.iph, &rt->u.dst, NULL); ip_select_ident(iph, &rt->u.dst, NULL);
nskb->nh.iph->protocol=IPPROTO_ICMP; iph->protocol=IPPROTO_ICMP;
nskb->nh.iph->saddr=rt->rt_src; iph->saddr=rt->rt_src;
nskb->nh.iph->daddr=rt->rt_dst; iph->daddr=rt->rt_dst;
nskb->nh.iph->check=0; iph->check=0;
nskb->nh.iph->check = ip_fast_csum(nskb->nh.raw, iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
nskb->nh.iph->ihl);
/* Set up ICMP header. */ /* Set up ICMP header. */
nskb->h.icmph = (struct icmphdr *)skb_put(nskb,sizeof(struct icmphdr)); icmph = nskb->h.icmph
nskb->h.icmph->type = ICMP_DEST_UNREACH; = (struct icmphdr *)skb_put(nskb, sizeof(struct icmphdr));
nskb->h.icmph->code = code; icmph->type = ICMP_DEST_UNREACH;
nskb->h.icmph->un.gateway = 0; icmph->code = code;
nskb->h.icmph->checksum = 0; icmph->un.gateway = 0;
icmph->checksum = 0;
/* Copy as much of original packet as will fit */ /* Copy as much of original packet as will fit */
data = skb_put(nskb, data = skb_put(nskb,
length - sizeof(struct iphdr) - sizeof(struct icmphdr)); length - sizeof(struct iphdr) - sizeof(struct icmphdr));
skb_copy_bits(skb_in, 0, data, skb_copy_bits(skb_in, 0, data,
length - sizeof(struct iphdr) - sizeof(struct icmphdr)); 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); connection_attach(nskb, skb_in->nfct);
...@@ -322,8 +388,11 @@ static unsigned int reject(struct sk_buff **pskb, ...@@ -322,8 +388,11 @@ static unsigned int reject(struct sk_buff **pskb,
case IPT_ICMP_HOST_PROHIBITED: case IPT_ICMP_HOST_PROHIBITED:
send_unreach(*pskb, ICMP_HOST_ANO); send_unreach(*pskb, ICMP_HOST_ANO);
break; break;
case IPT_ICMP_ADMIN_PROHIBITED:
send_unreach(*pskb, ICMP_PKT_FILTERED);
break;
case IPT_TCP_RESET: 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: case IPT_ICMP_ECHOREPLY:
/* Doesn't happen. */ /* Doesn't happen. */
break; break;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/netfilter_ipv4/ip_conntrack.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_conntrack_helper.h>
#include <linux/netfilter_ipv4/ip_tables.h> #include <linux/netfilter_ipv4/ip_tables.h>
#include <linux/netfilter_ipv4/ipt_helper.h> #include <linux/netfilter_ipv4/ipt_helper.h>
...@@ -34,6 +35,7 @@ match(const struct sk_buff *skb, ...@@ -34,6 +35,7 @@ match(const struct sk_buff *skb,
struct ip_conntrack_expect *exp; struct ip_conntrack_expect *exp;
struct ip_conntrack *ct; struct ip_conntrack *ct;
enum ip_conntrack_info ctinfo; enum ip_conntrack_info ctinfo;
int ret = 0;
ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo); ct = ip_conntrack_get((struct sk_buff *)skb, &ctinfo);
if (!ct) { if (!ct) {
...@@ -47,23 +49,27 @@ match(const struct sk_buff *skb, ...@@ -47,23 +49,27 @@ match(const struct sk_buff *skb,
} }
exp = ct->master; exp = ct->master;
READ_LOCK(&ip_conntrack_lock);
if (!exp->expectant) { if (!exp->expectant) {
DEBUGP("ipt_helper: expectation %p without expectant !?!\n", DEBUGP("ipt_helper: expectation %p without expectant !?!\n",
exp); exp);
return 0; goto out_unlock;
} }
if (!exp->expectant->helper) { if (!exp->expectant->helper) {
DEBUGP("ipt_helper: master ct %p has no helper\n", DEBUGP("ipt_helper: master ct %p has no helper\n",
exp->expectant); exp->expectant);
return 0; goto out_unlock;
} }
DEBUGP("master's name = %s , info->name = %s\n", DEBUGP("master's name = %s , info->name = %s\n",
exp->expectant->helper->name, info->name); exp->expectant->helper->name, info->name);
return !strncmp(exp->expectant->helper->name, info->name, ret = !strncmp(exp->expectant->helper->name, info->name,
strlen(exp->expectant->helper->name)) ^ info->invert; strlen(exp->expectant->helper->name)) ^ info->invert;
out_unlock:
READ_UNLOCK(&ip_conntrack_lock);
return ret;
} }
static int check(const char *tablename, static int check(const char *tablename,
......
...@@ -130,7 +130,7 @@ static spinlock_t addrconf_verify_lock = SPIN_LOCK_UNLOCKED; ...@@ -130,7 +130,7 @@ static spinlock_t addrconf_verify_lock = SPIN_LOCK_UNLOCKED;
static int addrconf_ifdown(struct net_device *dev, int how); 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_timer(unsigned long data);
static void addrconf_dad_completed(struct inet6_ifaddr *ifp); static void addrconf_dad_completed(struct inet6_ifaddr *ifp);
static void addrconf_rs_timer(unsigned long data); static void addrconf_rs_timer(unsigned long data);
...@@ -710,7 +710,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i ...@@ -710,7 +710,7 @@ static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, struct inet6_ifaddr *i
ift->prefered_lft = tmp_prefered_lft; ift->prefered_lft = tmp_prefered_lft;
ift->tstamp = ifp->tstamp; ift->tstamp = ifp->tstamp;
spin_unlock_bh(&ift->lock); spin_unlock_bh(&ift->lock);
addrconf_dad_start(ift); addrconf_dad_start(ift, 0);
in6_ifa_put(ift); in6_ifa_put(ift);
in6_dev_put(idev); in6_dev_put(idev);
out: out:
...@@ -1247,7 +1247,7 @@ static void addrconf_add_mroute(struct net_device *dev) ...@@ -1247,7 +1247,7 @@ static void addrconf_add_mroute(struct net_device *dev)
rtmsg.rtmsg_dst_len = 8; rtmsg.rtmsg_dst_len = 8;
rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF; rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
rtmsg.rtmsg_ifindex = dev->ifindex; rtmsg.rtmsg_ifindex = dev->ifindex;
rtmsg.rtmsg_flags = RTF_UP|RTF_ADDRCONF; rtmsg.rtmsg_flags = RTF_UP;
rtmsg.rtmsg_type = RTMSG_NEWROUTE; rtmsg.rtmsg_type = RTMSG_NEWROUTE;
ip6_route_add(&rtmsg, NULL, NULL); ip6_route_add(&rtmsg, NULL, NULL);
} }
...@@ -1274,7 +1274,7 @@ static void addrconf_add_lroute(struct net_device *dev) ...@@ -1274,7 +1274,7 @@ static void addrconf_add_lroute(struct net_device *dev)
struct in6_addr addr; struct in6_addr addr;
ipv6_addr_set(&addr, htonl(0xFE800000), 0, 0, 0); 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) 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) ...@@ -1367,7 +1367,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
} }
} else if (valid_lft) { } else if (valid_lft) {
addrconf_prefix_route(&pinfo->prefix, pinfo->prefix_len, 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) if (rt)
dst_release(&rt->u.dst); dst_release(&rt->u.dst);
...@@ -1413,7 +1413,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len) ...@@ -1413,7 +1413,7 @@ void addrconf_prefix_rcv(struct net_device *dev, u8 *opt, int len)
} }
update_lft = create = 1; update_lft = create = 1;
addrconf_dad_start(ifp); addrconf_dad_start(ifp, RTF_ADDRCONF|RTF_PREFIX_RT);
} }
if (ifp) { if (ifp) {
...@@ -1586,7 +1586,7 @@ static int inet6_addr_add(int ifindex, struct in6_addr *pfx, int plen) ...@@ -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); ifp = ipv6_add_addr(idev, pfx, plen, scope, IFA_F_PERMANENT);
if (!IS_ERR(ifp)) { if (!IS_ERR(ifp)) {
addrconf_dad_start(ifp); addrconf_dad_start(ifp, 0);
in6_ifa_put(ifp); in6_ifa_put(ifp);
return 0; return 0;
} }
...@@ -1761,7 +1761,7 @@ static void addrconf_add_linklocal(struct inet6_dev *idev, struct in6_addr *addr ...@@ -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); ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, IFA_F_PERMANENT);
if (!IS_ERR(ifp)) { if (!IS_ERR(ifp)) {
addrconf_dad_start(ifp); addrconf_dad_start(ifp, 0);
in6_ifa_put(ifp); in6_ifa_put(ifp);
} }
} }
...@@ -2021,8 +2021,7 @@ static void addrconf_rs_timer(unsigned long data) ...@@ -2021,8 +2021,7 @@ static void addrconf_rs_timer(unsigned long data)
memset(&rtmsg, 0, sizeof(struct in6_rtmsg)); memset(&rtmsg, 0, sizeof(struct in6_rtmsg));
rtmsg.rtmsg_type = RTMSG_NEWROUTE; rtmsg.rtmsg_type = RTMSG_NEWROUTE;
rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF; rtmsg.rtmsg_metric = IP6_RT_PRIO_ADDRCONF;
rtmsg.rtmsg_flags = (RTF_ALLONLINK | RTF_ADDRCONF | rtmsg.rtmsg_flags = (RTF_ALLONLINK | RTF_DEFAULT | RTF_UP);
RTF_DEFAULT | RTF_UP);
rtmsg.rtmsg_ifindex = ifp->idev->dev->ifindex; rtmsg.rtmsg_ifindex = ifp->idev->dev->ifindex;
...@@ -2036,7 +2035,7 @@ static void addrconf_rs_timer(unsigned long data) ...@@ -2036,7 +2035,7 @@ static void addrconf_rs_timer(unsigned long data)
/* /*
* Duplicate Address Detection * 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; struct net_device *dev;
unsigned long rand_num; unsigned long rand_num;
...@@ -2046,7 +2045,8 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp) ...@@ -2046,7 +2045,8 @@ static void addrconf_dad_start(struct inet6_ifaddr *ifp)
addrconf_join_solict(dev, &ifp->addr); addrconf_join_solict(dev, &ifp->addr);
if (ifp->prefix_len != 128 && (ifp->flags&IFA_F_PERMANENT)) 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]); net_srandom(ifp->addr.s6_addr32[3]);
rand_num = net_random() % (ifp->idev->cnf.rtr_solicit_delay ? : 1); rand_num = net_random() % (ifp->idev->cnf.rtr_solicit_delay ? : 1);
......
...@@ -1459,13 +1459,20 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, ...@@ -1459,13 +1459,20 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
struct in6_addr *src, struct in6_addr *src,
int iif, int iif,
int type, u32 pid, u32 seq, int type, u32 pid, u32 seq,
struct nlmsghdr *in_nlh) struct nlmsghdr *in_nlh, int prefix)
{ {
struct rtmsg *rtm; struct rtmsg *rtm;
struct nlmsghdr *nlh; struct nlmsghdr *nlh;
unsigned char *b = skb->tail; unsigned char *b = skb->tail;
struct rta_cacheinfo ci; 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) { if (!pid && in_nlh) {
pid = in_nlh->nlmsg_pid; pid = in_nlh->nlmsg_pid;
} }
...@@ -1546,10 +1553,17 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt, ...@@ -1546,10 +1553,17 @@ static int rt6_fill_node(struct sk_buff *skb, struct rt6_info *rt,
static int rt6_dump_route(struct rt6_info *rt, void *p_arg) 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 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, return rt6_fill_node(arg->skb, rt, NULL, NULL, 0, RTM_NEWROUTE,
NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq, NETLINK_CB(arg->cb->skb).pid, arg->cb->nlh->nlmsg_seq,
NULL); NULL, prefix);
} }
static int fib6_dump_node(struct fib6_walker_t *w) 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) ...@@ -1697,7 +1711,7 @@ int inet6_rtm_getroute(struct sk_buff *in_skb, struct nlmsghdr* nlh, void *arg)
&fl.fl6_dst, &fl.fl6_src, &fl.fl6_dst, &fl.fl6_src,
iif, iif,
RTM_NEWROUTE, NETLINK_CB(in_skb).pid, RTM_NEWROUTE, NETLINK_CB(in_skb).pid,
nlh->nlmsg_seq, nlh); nlh->nlmsg_seq, nlh, 0);
if (err < 0) { if (err < 0) {
err = -EMSGSIZE; err = -EMSGSIZE;
goto out_free; goto out_free;
...@@ -1723,7 +1737,7 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nlmsghdr *nlh) ...@@ -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); netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, ENOBUFS);
return; 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); kfree_skb(skb);
netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, EINVAL); netlink_set_err(rtnl, 0, RTMGRP_IPV6_ROUTE, EINVAL);
return; return;
......
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