Commit d027a95f authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://kernel.bkbits.net/davem/net-2.6

into home.osdl.org:/home/torvalds/v2.5/linux
parents b2e95563 09fa6bce
...@@ -71,12 +71,10 @@ static inline ...@@ -71,12 +71,10 @@ static inline
void nf_bridge_maybe_copy_header(struct sk_buff *skb) void nf_bridge_maybe_copy_header(struct sk_buff *skb)
{ {
if (skb->nf_bridge) { if (skb->nf_bridge) {
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
if (skb->protocol == __constant_htons(ETH_P_8021Q)) { if (skb->protocol == __constant_htons(ETH_P_8021Q)) {
memcpy(skb->data - 18, skb->nf_bridge->hh, 18); memcpy(skb->data - 18, skb->nf_bridge->hh, 18);
skb_push(skb, 4); skb_push(skb, 4);
} else } else
#endif
memcpy(skb->data - 16, skb->nf_bridge->hh, 16); memcpy(skb->data - 16, skb->nf_bridge->hh, 16);
} }
} }
...@@ -86,10 +84,9 @@ void nf_bridge_save_header(struct sk_buff *skb) ...@@ -86,10 +84,9 @@ void nf_bridge_save_header(struct sk_buff *skb)
{ {
int header_size = 16; int header_size = 16;
#if defined(CONFIG_VLAN_8021Q) || defined(CONFIG_VLAN_8021Q_MODULE)
if (skb->protocol == __constant_htons(ETH_P_8021Q)) if (skb->protocol == __constant_htons(ETH_P_8021Q))
header_size = 18; header_size = 18;
#endif
memcpy(skb->nf_bridge->hh, skb->data - header_size, header_size); memcpy(skb->nf_bridge->hh, skb->data - header_size, header_size);
} }
......
...@@ -386,7 +386,10 @@ struct tcp_sock { ...@@ -386,7 +386,10 @@ struct tcp_sock {
struct tcp_opt tcp; struct tcp_opt tcp;
}; };
#define tcp_sk(__sk) (&((struct tcp_sock *)__sk)->tcp) static inline struct tcp_opt * tcp_sk(const struct sock *__sk)
{
return &((struct tcp_sock *)__sk)->tcp;
}
#endif #endif
......
...@@ -90,7 +90,6 @@ ...@@ -90,7 +90,6 @@
#include <net/snmp.h> #include <net/snmp.h>
#include <net/sctp/structs.h> #include <net/sctp/structs.h>
#include <net/sctp/constants.h> #include <net/sctp/constants.h>
#include <net/sctp/sm.h>
/* Set SCTP_DEBUG flag via config if not already set. */ /* Set SCTP_DEBUG flag via config if not already set. */
......
...@@ -542,24 +542,9 @@ static inline struct inode *SOCK_INODE(struct socket *socket) ...@@ -542,24 +542,9 @@ static inline struct inode *SOCK_INODE(struct socket *socket)
extern void __lock_sock(struct sock *sk); extern void __lock_sock(struct sock *sk);
extern void __release_sock(struct sock *sk); extern void __release_sock(struct sock *sk);
#define sock_owned_by_user(sk) ((sk)->sk_lock.owner) #define sock_owned_by_user(sk) ((sk)->sk_lock.owner)
#define lock_sock(__sk) \
do { might_sleep(); \
spin_lock_bh(&((__sk)->sk_lock.slock)); \
if ((__sk)->sk_lock.owner) \
__lock_sock(__sk); \
(__sk)->sk_lock.owner = (void *)1; \
spin_unlock_bh(&((__sk)->sk_lock.slock)); \
} while(0)
#define release_sock(__sk) \ extern void lock_sock(struct sock *sk);
do { spin_lock_bh(&((__sk)->sk_lock.slock)); \ extern void release_sock(struct sock *sk);
if ((__sk)->sk_backlog.tail) \
__release_sock(__sk); \
(__sk)->sk_lock.owner = NULL; \
if (waitqueue_active(&((__sk)->sk_lock.wq))) \
wake_up(&((__sk)->sk_lock.wq)); \
spin_unlock_bh(&((__sk)->sk_lock.slock)); \
} while(0)
/* BH context may only use the following locking interface. */ /* BH context may only use the following locking interface. */
#define bh_lock_sock(__sk) spin_lock(&((__sk)->sk_lock.slock)) #define bh_lock_sock(__sk) spin_lock(&((__sk)->sk_lock.slock))
......
...@@ -860,7 +860,7 @@ extern void xfrm_policy_flush(void); ...@@ -860,7 +860,7 @@ extern void xfrm_policy_flush(void);
extern void xfrm_policy_kill(struct xfrm_policy *); extern void xfrm_policy_kill(struct xfrm_policy *);
extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
extern struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl); extern struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl);
extern int xfrm_flush_bundles(struct xfrm_state *x); extern int xfrm_flush_bundles(void);
extern wait_queue_head_t km_waitq; extern wait_queue_head_t km_waitq;
extern void km_state_expired(struct xfrm_state *x, int hard); extern void km_state_expired(struct xfrm_state *x, int hard);
......
...@@ -23,6 +23,7 @@ static struct ctl_table atalk_table[] = { ...@@ -23,6 +23,7 @@ static struct ctl_table atalk_table[] = {
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
}, },
{ {
.ctl_name = NET_ATALK_AARP_TICK_TIME, .ctl_name = NET_ATALK_AARP_TICK_TIME,
...@@ -31,6 +32,7 @@ static struct ctl_table atalk_table[] = { ...@@ -31,6 +32,7 @@ static struct ctl_table atalk_table[] = {
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
}, },
{ {
.ctl_name = NET_ATALK_AARP_RETRANSMIT_LIMIT, .ctl_name = NET_ATALK_AARP_RETRANSMIT_LIMIT,
...@@ -47,6 +49,7 @@ static struct ctl_table atalk_table[] = { ...@@ -47,6 +49,7 @@ static struct ctl_table atalk_table[] = {
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
}, },
{ 0 }, { 0 },
}; };
......
...@@ -356,6 +356,7 @@ static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff **pskb, ...@@ -356,6 +356,7 @@ static unsigned int br_nf_local_in(unsigned int hook, struct sk_buff **pskb,
return NF_ACCEPT; return NF_ACCEPT;
} }
/* PF_BRIDGE/FORWARD *************************************************/ /* PF_BRIDGE/FORWARD *************************************************/
static int br_nf_forward_finish(struct sk_buff *skb) static int br_nf_forward_finish(struct sk_buff *skb)
{ {
...@@ -466,6 +467,7 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb, ...@@ -466,6 +467,7 @@ static unsigned int br_nf_forward_arp(unsigned int hook, struct sk_buff **pskb,
return NF_STOLEN; return NF_STOLEN;
} }
/* PF_BRIDGE/LOCAL_OUT ***********************************************/ /* PF_BRIDGE/LOCAL_OUT ***********************************************/
static int br_nf_local_out_finish(struct sk_buff *skb) static int br_nf_local_out_finish(struct sk_buff *skb)
{ {
...@@ -531,9 +533,7 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb, ...@@ -531,9 +533,7 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff **pskb,
return NF_ACCEPT; return NF_ACCEPT;
nf_bridge = skb->nf_bridge; nf_bridge = skb->nf_bridge;
nf_bridge->physoutdev = skb->dev; nf_bridge->physoutdev = skb->dev;
realindev = nf_bridge->physindev; realindev = nf_bridge->physindev;
/* Bridged, take PF_BRIDGE/FORWARD. /* Bridged, take PF_BRIDGE/FORWARD.
...@@ -601,18 +601,15 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, ...@@ -601,18 +601,15 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet); struct vlan_ethhdr *hdr = (struct vlan_ethhdr *)(skb->mac.ethernet);
struct net_device *realoutdev = bridge_parent(skb->dev); struct net_device *realoutdev = bridge_parent(skb->dev);
/* Be very paranoid. Must be a device driver bug. */ #ifdef CONFIG_NETFILTER_DEBUG
/* Be very paranoid. This probably won't happen anymore, but let's
* keep the check just to be sure... */
if (skb->mac.raw < skb->head || skb->mac.raw + ETH_HLEN > skb->data) { if (skb->mac.raw < skb->head || skb->mac.raw + ETH_HLEN > skb->data) {
printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: " printk(KERN_CRIT "br_netfilter: Argh!! br_nf_post_routing: "
"bad mac.raw pointer."); "bad mac.raw pointer.");
if (skb->dev != NULL) { goto print_error;
printk("[%s]", skb->dev->name);
if (has_bridge_parent(skb->dev))
printk("[%s]", bridge_parent(skb->dev)->name);
}
printk(" head:%p, raw:%p\n", skb->head, skb->mac.raw);
return NF_ACCEPT;
} }
#endif
#ifdef CONFIG_SYSCTL #ifdef CONFIG_SYSCTL
if (!nf_bridge) if (!nf_bridge)
...@@ -622,13 +619,16 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, ...@@ -622,13 +619,16 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
if (skb->protocol != __constant_htons(ETH_P_IP) && !IS_VLAN_IP) if (skb->protocol != __constant_htons(ETH_P_IP) && !IS_VLAN_IP)
return NF_ACCEPT; return NF_ACCEPT;
#ifdef CONFIG_NETFILTER_DEBUG
/* Sometimes we get packets with NULL ->dst here (for example, /* Sometimes we get packets with NULL ->dst here (for example,
* running a dhcp client daemon triggers this). * running a dhcp client daemon triggers this). This should now
* be fixed, but let's keep the check around.
*/ */
if (skb->dst == NULL) if (skb->dst == NULL) {
return NF_ACCEPT; printk(KERN_CRIT "br_netfilter: skb->dst == NULL.");
goto print_error;
}
#ifdef CONFIG_NETFILTER_DEBUG
skb->nf_debug ^= (1 << NF_IP_POST_ROUTING); skb->nf_debug ^= (1 << NF_IP_POST_ROUTING);
#endif #endif
...@@ -655,6 +655,18 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb, ...@@ -655,6 +655,18 @@ static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff **pskb,
realoutdev, br_dev_queue_push_xmit); realoutdev, br_dev_queue_push_xmit);
return NF_STOLEN; return NF_STOLEN;
#ifdef CONFIG_NETFILTER_DEBUG
print_error:
if (skb->dev != NULL) {
printk("[%s]", skb->dev->name);
if (has_bridge_parent(skb->dev))
printk("[%s]", bridge_parent(skb->dev)->name);
}
printk(" head:%p, raw:%p, data:%p\n", skb->head, skb->mac.raw,
skb->data);
return NF_ACCEPT;
#endif
} }
......
...@@ -1543,7 +1543,7 @@ static inline int __handle_bridge(struct sk_buff *skb, ...@@ -1543,7 +1543,7 @@ static inline int __handle_bridge(struct sk_buff *skb,
struct packet_type **pt_prev, int *ret) struct packet_type **pt_prev, int *ret)
{ {
#if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE) #if defined(CONFIG_BRIDGE) || defined(CONFIG_BRIDGE_MODULE)
if (skb->dev->br_port) { if (skb->dev->br_port && skb->pkt_type != PACKET_LOOPBACK) {
*ret = handle_bridge(skb, *pt_prev); *ret = handle_bridge(skb, *pt_prev);
if (br_handle_frame_hook(skb) == 0) if (br_handle_frame_hook(skb) == 0)
return 1; return 1;
......
...@@ -1518,6 +1518,7 @@ struct neigh_sysctl_table { ...@@ -1518,6 +1518,7 @@ struct neigh_sysctl_table {
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
}, },
{ {
.ctl_name = NET_NEIGH_DELAY_PROBE_TIME, .ctl_name = NET_NEIGH_DELAY_PROBE_TIME,
...@@ -1525,6 +1526,7 @@ struct neigh_sysctl_table { ...@@ -1525,6 +1526,7 @@ struct neigh_sysctl_table {
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
}, },
{ {
.ctl_name = NET_NEIGH_GC_STALE_TIME, .ctl_name = NET_NEIGH_GC_STALE_TIME,
...@@ -1532,6 +1534,7 @@ struct neigh_sysctl_table { ...@@ -1532,6 +1534,7 @@ struct neigh_sysctl_table {
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
}, },
{ {
.ctl_name = NET_NEIGH_UNRES_QLEN, .ctl_name = NET_NEIGH_UNRES_QLEN,
...@@ -1574,6 +1577,7 @@ struct neigh_sysctl_table { ...@@ -1574,6 +1577,7 @@ struct neigh_sysctl_table {
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
}, },
{ {
.ctl_name = NET_NEIGH_GC_THRESH1, .ctl_name = NET_NEIGH_GC_THRESH1,
......
...@@ -1119,6 +1119,31 @@ void sock_init_data(struct socket *sock, struct sock *sk) ...@@ -1119,6 +1119,31 @@ void sock_init_data(struct socket *sock, struct sock *sk)
atomic_set(&sk->sk_refcnt, 1); atomic_set(&sk->sk_refcnt, 1);
} }
void lock_sock(struct sock *sk)
{
might_sleep();
spin_lock_bh(&(sk->sk_lock.slock));
if (sk->sk_lock.owner)
__lock_sock(sk);
sk->sk_lock.owner = (void *)1;
spin_unlock_bh(&(sk->sk_lock.slock));
}
EXPORT_SYMBOL(lock_sock);
void release_sock(struct sock *sk)
{
spin_lock_bh(&(sk->sk_lock.slock));
if (sk->sk_backlog.tail)
__release_sock(sk);
sk->sk_lock.owner = NULL;
if (waitqueue_active(&(sk->sk_lock.wq)))
wake_up(&(sk->sk_lock.wq));
spin_unlock_bh(&(sk->sk_lock.slock));
}
EXPORT_SYMBOL(release_sock);
EXPORT_SYMBOL(__lock_sock); EXPORT_SYMBOL(__lock_sock);
EXPORT_SYMBOL(__release_sock); EXPORT_SYMBOL(__release_sock);
EXPORT_SYMBOL(sk_alloc); EXPORT_SYMBOL(sk_alloc);
......
...@@ -146,7 +146,8 @@ ctl_table core_table[] = { ...@@ -146,7 +146,8 @@ ctl_table core_table[] = {
.data = &net_msg_cost, .data = &net_msg_cost,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies .proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
}, },
{ {
.ctl_name = NET_CORE_MSG_BURST, .ctl_name = NET_CORE_MSG_BURST,
...@@ -154,7 +155,8 @@ ctl_table core_table[] = { ...@@ -154,7 +155,8 @@ ctl_table core_table[] = {
.data = &net_msg_burst, .data = &net_msg_burst,
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies .proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
}, },
{ {
.ctl_name = NET_CORE_OPTMEM_MAX, .ctl_name = NET_CORE_OPTMEM_MAX,
......
...@@ -91,8 +91,10 @@ static struct recent_ip_tables *r_tables = NULL; ...@@ -91,8 +91,10 @@ static struct recent_ip_tables *r_tables = NULL;
*/ */
static spinlock_t recent_lock = SPIN_LOCK_UNLOCKED; static spinlock_t recent_lock = SPIN_LOCK_UNLOCKED;
#ifdef CONFIG_PROC_FS
/* Our /proc/net/ipt_recent entry */ /* Our /proc/net/ipt_recent entry */
static struct proc_dir_entry *proc_net_ipt_recent = NULL; static struct proc_dir_entry *proc_net_ipt_recent = NULL;
#endif
/* Function declaration for later. */ /* Function declaration for later. */
static int static int
...@@ -959,8 +961,10 @@ static int __init init(void) ...@@ -959,8 +961,10 @@ static int __init init(void)
int count; int count;
printk(version); printk(version);
#ifdef CONFIG_PROC_FS
proc_net_ipt_recent = proc_mkdir("ipt_recent",proc_net); proc_net_ipt_recent = proc_mkdir("ipt_recent",proc_net);
if(!proc_net_ipt_recent) return -ENOMEM; if(!proc_net_ipt_recent) return -ENOMEM;
#endif
if(ip_list_hash_size && ip_list_hash_size <= ip_list_tot) { if(ip_list_hash_size && ip_list_hash_size <= ip_list_tot) {
printk(KERN_WARNING RECENT_NAME ": ip_list_hash_size too small, resetting to default.\n"); printk(KERN_WARNING RECENT_NAME ": ip_list_hash_size too small, resetting to default.\n");
......
...@@ -2946,6 +2946,7 @@ static struct addrconf_sysctl_table ...@@ -2946,6 +2946,7 @@ static struct addrconf_sysctl_table
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
}, },
{ {
.ctl_name = NET_IPV6_RTR_SOLICIT_DELAY, .ctl_name = NET_IPV6_RTR_SOLICIT_DELAY,
...@@ -2954,6 +2955,7 @@ static struct addrconf_sysctl_table ...@@ -2954,6 +2955,7 @@ static struct addrconf_sysctl_table
.maxlen = sizeof(int), .maxlen = sizeof(int),
.mode = 0644, .mode = 0644,
.proc_handler = &proc_dointvec_jiffies, .proc_handler = &proc_dointvec_jiffies,
.strategy = &sysctl_jiffies,
}, },
#ifdef CONFIG_IPV6_PRIVACY #ifdef CONFIG_IPV6_PRIVACY
{ {
......
...@@ -75,6 +75,9 @@ ...@@ -75,6 +75,9 @@
#include <net/checksum.h> #include <net/checksum.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv6.h>
static struct socket *ndisc_socket; static struct socket *ndisc_socket;
static u32 ndisc_hash(const void *pkey, const struct net_device *dev); static u32 ndisc_hash(const void *pkey, const struct net_device *dev);
...@@ -497,10 +500,11 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, ...@@ -497,10 +500,11 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
skb->dst = dst; skb->dst = dst;
idev = in6_dev_get(dst->dev); idev = in6_dev_get(dst->dev);
dst_output(skb); err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);
if (!err) {
ICMP6_INC_STATS(idev, Icmp6OutNeighborAdvertisements); ICMP6_INC_STATS(idev, Icmp6OutNeighborAdvertisements);
ICMP6_INC_STATS(idev, Icmp6OutMsgs); ICMP6_INC_STATS(idev, Icmp6OutMsgs);
}
if (likely(idev != NULL)) if (likely(idev != NULL))
in6_dev_put(idev); in6_dev_put(idev);
...@@ -576,10 +580,11 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, ...@@ -576,10 +580,11 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
/* send it! */ /* send it! */
skb->dst = dst; skb->dst = dst;
idev = in6_dev_get(dst->dev); idev = in6_dev_get(dst->dev);
dst_output(skb); err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);
if (!err) {
ICMP6_INC_STATS(idev, Icmp6OutNeighborSolicits); ICMP6_INC_STATS(idev, Icmp6OutNeighborSolicits);
ICMP6_INC_STATS(idev, Icmp6OutMsgs); ICMP6_INC_STATS(idev, Icmp6OutMsgs);
}
if (likely(idev != NULL)) if (likely(idev != NULL))
in6_dev_put(idev); in6_dev_put(idev);
...@@ -644,10 +649,11 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, ...@@ -644,10 +649,11 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
/* send it! */ /* send it! */
skb->dst = dst; skb->dst = dst;
idev = in6_dev_get(dst->dev); idev = in6_dev_get(dst->dev);
dst_output(skb); err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL, dst->dev, dst_output);
if (!err) {
ICMP6_INC_STATS(idev, Icmp6OutRouterSolicits); ICMP6_INC_STATS(idev, Icmp6OutRouterSolicits);
ICMP6_INC_STATS(idev, Icmp6OutMsgs); ICMP6_INC_STATS(idev, Icmp6OutMsgs);
}
if (likely(idev != NULL)) if (likely(idev != NULL))
in6_dev_put(idev); in6_dev_put(idev);
...@@ -1404,10 +1410,11 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, ...@@ -1404,10 +1410,11 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
buff->dst = dst; buff->dst = dst;
idev = in6_dev_get(dst->dev); idev = in6_dev_get(dst->dev);
dst_output(buff); err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, buff, NULL, dst->dev, dst_output);
if (!err) {
ICMP6_INC_STATS(idev, Icmp6OutRedirects); ICMP6_INC_STATS(idev, Icmp6OutRedirects);
ICMP6_INC_STATS(idev, Icmp6OutMsgs); ICMP6_INC_STATS(idev, Icmp6OutMsgs);
}
if (likely(idev != NULL)) if (likely(idev != NULL))
in6_dev_put(idev); in6_dev_put(idev);
......
...@@ -58,6 +58,7 @@ ...@@ -58,6 +58,7 @@
#include <linux/in.h> #include <linux/in.h>
#include <net/ipv6.h> #include <net/ipv6.h>
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
/* Forward declarations for internal functions. */ /* Forward declarations for internal functions. */
static void sctp_assoc_bh_rcv(struct sctp_association *asoc); static void sctp_assoc_bh_rcv(struct sctp_association *asoc);
......
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
#include <net/sock.h> /* For skb_set_owner_w */ #include <net/sock.h> /* For skb_set_owner_w */
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
/* Declare internal functions here. */ /* Declare internal functions here. */
static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn); static int sctp_acked(struct sctp_sackhdr *sack, __u32 tsn);
......
...@@ -77,6 +77,7 @@ ...@@ -77,6 +77,7 @@
#include <linux/socket.h> /* for sa_family_t */ #include <linux/socket.h> /* for sa_family_t */
#include <net/sock.h> #include <net/sock.h>
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
/* WARNING: Please do not remove the SCTP_STATIC attribute to /* WARNING: Please do not remove the SCTP_STATIC attribute to
* any of the functions below as they are used to export functions * any of the functions below as they are used to export functions
......
...@@ -50,6 +50,7 @@ ...@@ -50,6 +50,7 @@
#include <linux/types.h> #include <linux/types.h>
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
/* 1st Level Abstractions. */ /* 1st Level Abstractions. */
......
...@@ -19,6 +19,8 @@ ...@@ -19,6 +19,8 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/notifier.h>
#include <linux/netdevice.h>
#include <net/xfrm.h> #include <net/xfrm.h>
#include <net/ip.h> #include <net/ip.h>
...@@ -690,6 +692,8 @@ static inline int policy_to_flow_dir(int dir) ...@@ -690,6 +692,8 @@ static inline int policy_to_flow_dir(int dir)
}; };
} }
static int stale_bundle(struct dst_entry *dst);
/* Main function: finds/creates a bundle for given flow. /* Main function: finds/creates a bundle for given flow.
* *
* At the moment we eat a raw IP route. Mostly to speed up lookups * At the moment we eat a raw IP route. Mostly to speed up lookups
...@@ -814,10 +818,11 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl, ...@@ -814,10 +818,11 @@ int xfrm_lookup(struct dst_entry **dst_p, struct flowi *fl,
} }
write_lock_bh(&policy->lock); write_lock_bh(&policy->lock);
if (unlikely(policy->dead)) { if (unlikely(policy->dead || stale_bundle(dst))) {
/* Wow! While we worked on resolving, this /* Wow! While we worked on resolving, this
* policy has gone. Retry. It is not paranoia, * policy has gone. Retry. It is not paranoia,
* we just cannot enlist new bundle to dead object. * we just cannot enlist new bundle to dead object.
* We can't enlist stable bundles either.
*/ */
write_unlock_bh(&policy->lock); write_unlock_bh(&policy->lock);
...@@ -984,19 +989,28 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family) ...@@ -984,19 +989,28 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
/* Optimize later using cookies and generation ids. */ /* Optimize later using cookies and generation ids. */
static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie) static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie)
{
if (!stale_bundle(dst))
return dst;
dst_release(dst);
return NULL;
}
static int stale_bundle(struct dst_entry *dst)
{ {
struct dst_entry *child = dst; struct dst_entry *child = dst;
while (child) { while (child) {
if (child->obsolete > 0 || if (child->obsolete > 0 ||
(child->dev && !netif_running(child->dev)) ||
(child->xfrm && child->xfrm->km.state != XFRM_STATE_VALID)) { (child->xfrm && child->xfrm->km.state != XFRM_STATE_VALID)) {
dst_release(dst); return 1;
return NULL;
} }
child = child->child; child = child->child;
} }
return dst; return 0;
} }
static void xfrm_dst_destroy(struct dst_entry *dst) static void xfrm_dst_destroy(struct dst_entry *dst)
...@@ -1022,7 +1036,7 @@ static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst) ...@@ -1022,7 +1036,7 @@ static struct dst_entry *xfrm_negative_advice(struct dst_entry *dst)
return dst; return dst;
} }
static void __xfrm_garbage_collect(void) static void xfrm_prune_bundles(int (*func)(struct dst_entry *))
{ {
int i; int i;
struct xfrm_policy *pol; struct xfrm_policy *pol;
...@@ -1034,7 +1048,7 @@ static void __xfrm_garbage_collect(void) ...@@ -1034,7 +1048,7 @@ static void __xfrm_garbage_collect(void)
write_lock(&pol->lock); write_lock(&pol->lock);
dstp = &pol->bundles; dstp = &pol->bundles;
while ((dst=*dstp) != NULL) { while ((dst=*dstp) != NULL) {
if (atomic_read(&dst->__refcnt) == 0) { if (func(dst)) {
*dstp = dst->next; *dstp = dst->next;
dst->next = gc_list; dst->next = gc_list;
gc_list = dst; gc_list = dst;
...@@ -1054,46 +1068,19 @@ static void __xfrm_garbage_collect(void) ...@@ -1054,46 +1068,19 @@ static void __xfrm_garbage_collect(void)
} }
} }
static int bundle_depends_on(struct dst_entry *dst, struct xfrm_state *x) static int unused_bundle(struct dst_entry *dst)
{ {
do { return !atomic_read(&dst->__refcnt);
if (dst->xfrm == x)
return 1;
} while ((dst = dst->child) != NULL);
return 0;
} }
int xfrm_flush_bundles(struct xfrm_state *x) static void __xfrm_garbage_collect(void)
{ {
int i; xfrm_prune_bundles(unused_bundle);
struct xfrm_policy *pol; }
struct dst_entry *dst, **dstp, *gc_list = NULL;
read_lock_bh(&xfrm_policy_lock);
for (i=0; i<2*XFRM_POLICY_MAX; i++) {
for (pol = xfrm_policy_list[i]; pol; pol = pol->next) {
write_lock(&pol->lock);
dstp = &pol->bundles;
while ((dst=*dstp) != NULL) {
if (bundle_depends_on(dst, x)) {
*dstp = dst->next;
dst->next = gc_list;
gc_list = dst;
} else {
dstp = &dst->next;
}
}
write_unlock(&pol->lock);
}
}
read_unlock_bh(&xfrm_policy_lock);
while (gc_list) {
dst = gc_list;
gc_list = dst->next;
dst_free(dst);
}
int xfrm_flush_bundles(void)
{
xfrm_prune_bundles(stale_bundle);
return 0; return 0;
} }
...@@ -1216,6 +1203,21 @@ void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo) ...@@ -1216,6 +1203,21 @@ void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo)
read_unlock(&afinfo->lock); read_unlock(&afinfo->lock);
} }
static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
{
switch (event) {
case NETDEV_DOWN:
xfrm_flush_bundles();
}
return NOTIFY_DONE;
}
struct notifier_block xfrm_dev_notifier = {
xfrm_dev_event,
NULL,
0
};
void __init xfrm_policy_init(void) void __init xfrm_policy_init(void)
{ {
xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache", xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache",
...@@ -1226,6 +1228,7 @@ void __init xfrm_policy_init(void) ...@@ -1226,6 +1228,7 @@ void __init xfrm_policy_init(void)
panic("XFRM: failed to allocate xfrm_dst_cache\n"); panic("XFRM: failed to allocate xfrm_dst_cache\n");
INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task, NULL); INIT_WORK(&xfrm_policy_gc_work, xfrm_policy_gc_task, NULL);
register_netdevice_notifier(&xfrm_dev_notifier);
} }
void __init xfrm_init(void) void __init xfrm_init(void)
......
...@@ -219,7 +219,7 @@ static void __xfrm_state_delete(struct xfrm_state *x) ...@@ -219,7 +219,7 @@ static void __xfrm_state_delete(struct xfrm_state *x)
* there are DSTs attached to this xfrm_state. * there are DSTs attached to this xfrm_state.
*/ */
if (atomic_read(&x->refcnt) > 2) if (atomic_read(&x->refcnt) > 2)
xfrm_flush_bundles(x); xfrm_flush_bundles();
/* All xfrm_state objects are created by one of two possible /* All xfrm_state objects are created by one of two possible
* paths: * paths:
......
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