Commit 5b4e71d0 authored by David S. Miller's avatar David S. Miller

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

into nuts.ninka.net:/home/davem/src/BK/net-2.5
parents 51544df2 be67585e
...@@ -61,7 +61,11 @@ extern struct rt6_info *rt6_lookup(struct in6_addr *daddr, ...@@ -61,7 +61,11 @@ extern struct rt6_info *rt6_lookup(struct in6_addr *daddr,
struct in6_addr *saddr, struct in6_addr *saddr,
int oif, int flags); int oif, int flags);
extern struct rt6_info *ip6_dst_alloc(void); extern struct dst_entry *ndisc_dst_alloc(struct net_device *dev,
struct neighbour *neigh,
int (*output)(struct sk_buff *));
extern int ndisc_dst_gc(int *more);
extern void fib6_force_start_gc(void);
/* /*
* support functions for ND * support functions for ND
......
...@@ -405,34 +405,6 @@ static int do_set_attach_filter(int fd, int level, int optname, ...@@ -405,34 +405,6 @@ static int do_set_attach_filter(int fd, int level, int optname,
sizeof(struct sock_fprog)); sizeof(struct sock_fprog));
} }
static int do_set_icmpv6_filter(int fd, int level, int optname,
char *optval, int optlen)
{
struct icmp6_filter kfilter;
mm_segment_t old_fs;
int ret, i;
if (optlen < sizeof(kfilter))
return -EINVAL;
if (copy_from_user(&kfilter, optval, sizeof(kfilter)))
return -EFAULT;
for (i = 0; i < 8; i += 2) {
u32 tmp = kfilter.data[i];
kfilter.data[i] = kfilter.data[i + 1];
kfilter.data[i + 1] = tmp;
}
old_fs = get_fs();
set_fs(KERNEL_DS);
ret = sys_setsockopt(fd, level, optname,
(char *) &kfilter, sizeof(kfilter));
set_fs(old_fs);
return ret;
}
static int do_set_sock_timeout(int fd, int level, int optname, char *optval, int optlen) static int do_set_sock_timeout(int fd, int level, int optname, char *optval, int optlen)
{ {
struct compat_timeval *up = (struct compat_timeval *) optval; struct compat_timeval *up = (struct compat_timeval *) optval;
...@@ -465,9 +437,6 @@ asmlinkage long compat_sys_setsockopt(int fd, int level, int optname, ...@@ -465,9 +437,6 @@ asmlinkage long compat_sys_setsockopt(int fd, int level, int optname,
optval, optlen); optval, optlen);
if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO) if (optname == SO_RCVTIMEO || optname == SO_SNDTIMEO)
return do_set_sock_timeout(fd, level, optname, optval, optlen); return do_set_sock_timeout(fd, level, optname, optval, optlen);
if (level == SOL_ICMPV6 && optname == ICMPV6_FILTER)
return do_set_icmpv6_filter(fd, level, optname,
optval, optlen);
return sys_setsockopt(fd, level, optname, optval, optlen); return sys_setsockopt(fd, level, optname, optval, optlen);
} }
......
...@@ -496,6 +496,12 @@ static __inline__ void fib6_start_gc(struct rt6_info *rt) ...@@ -496,6 +496,12 @@ static __inline__ void fib6_start_gc(struct rt6_info *rt)
mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval); mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval);
} }
void fib6_force_start_gc(void)
{
if (ip6_fib_timer.expires == 0)
mod_timer(&ip6_fib_timer, jiffies + ip6_rt_gc_interval);
}
/* /*
* Add routing information to the routing tree. * Add routing information to the routing tree.
* <destination addr>/<source addr> * <destination addr>/<source addr>
...@@ -1214,6 +1220,7 @@ void fib6_run_gc(unsigned long dummy) ...@@ -1214,6 +1220,7 @@ void fib6_run_gc(unsigned long dummy)
write_lock_bh(&rt6_lock); write_lock_bh(&rt6_lock);
ndisc_dst_gc(&gc_args.more);
fib6_clean_tree(&ip6_routing_table, fib6_age, 0, NULL); fib6_clean_tree(&ip6_routing_table, fib6_age, 0, NULL);
write_unlock_bh(&rt6_lock); write_unlock_bh(&rt6_lock);
......
...@@ -402,25 +402,6 @@ static int ndisc_output(struct sk_buff *skb) ...@@ -402,25 +402,6 @@ static int ndisc_output(struct sk_buff *skb)
return -EINVAL; return -EINVAL;
} }
static inline struct dst_entry *ndisc_dst_alloc(struct net_device *dev,
struct neighbour *neigh)
{
struct rt6_info *rt = ip6_dst_alloc();
if (unlikely(rt == NULL))
goto out;
rt->rt6i_dev = dev;
rt->rt6i_nexthop = neigh;
rt->rt6i_expires = 0;
rt->rt6i_flags = RTF_LOCAL;
rt->rt6i_metric = 0;
rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255;
rt->u.dst.output = ndisc_output;
out:
return (struct dst_entry *)rt;
}
static inline void ndisc_flow_init(struct flowi *fl, u8 type, static inline void ndisc_flow_init(struct flowi *fl, u8 type,
struct in6_addr *saddr, struct in6_addr *daddr) struct in6_addr *saddr, struct in6_addr *daddr)
{ {
...@@ -463,13 +444,13 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, ...@@ -463,13 +444,13 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr); ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr);
dst = ndisc_dst_alloc(dev, neigh); dst = ndisc_dst_alloc(dev, neigh, ndisc_output);
if (!dst) if (!dst)
return; return;
err = xfrm_lookup(&dst, &fl, NULL, 0); err = xfrm_lookup(&dst, &fl, NULL, 0);
if (err < 0) { if (err < 0) {
dst_free(dst); dst_release(dst);
return; return;
} }
...@@ -485,7 +466,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, ...@@ -485,7 +466,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
if (skb == NULL) { if (skb == NULL) {
ND_PRINTK1("send_na: alloc skb failed\n"); ND_PRINTK1("send_na: alloc skb failed\n");
dst_free(dst); dst_release(dst);
return; return;
} }
...@@ -515,7 +496,6 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh, ...@@ -515,7 +496,6 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
csum_partial((__u8 *) msg, csum_partial((__u8 *) msg,
len, 0)); len, 0));
dst_clone(dst);
skb->dst = dst; skb->dst = dst;
idev = in6_dev_get(dst->dev); idev = in6_dev_get(dst->dev);
dst_output(skb); dst_output(skb);
...@@ -550,10 +530,9 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, ...@@ -550,10 +530,9 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr); ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr);
dst = ndisc_dst_alloc(dev, neigh); dst = ndisc_dst_alloc(dev, neigh, ndisc_output);
if (!dst) if (!dst)
return; return;
dst_clone(dst);
err = xfrm_lookup(&dst, &fl, NULL, 0); err = xfrm_lookup(&dst, &fl, NULL, 0);
if (err < 0) { if (err < 0) {
...@@ -570,6 +549,7 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, ...@@ -570,6 +549,7 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
1, &err); 1, &err);
if (skb == NULL) { if (skb == NULL) {
ND_PRINTK1("send_ns: alloc skb failed\n"); ND_PRINTK1("send_ns: alloc skb failed\n");
dst_release(dst);
return; return;
} }
...@@ -595,7 +575,6 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh, ...@@ -595,7 +575,6 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
csum_partial((__u8 *) msg, csum_partial((__u8 *) msg,
len, 0)); len, 0));
/* send it! */ /* send it! */
dst_clone(dst);
skb->dst = dst; skb->dst = dst;
idev = in6_dev_get(dst->dev); idev = in6_dev_get(dst->dev);
dst_output(skb); dst_output(skb);
...@@ -622,10 +601,9 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, ...@@ -622,10 +601,9 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr); ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr);
dst = ndisc_dst_alloc(dev, NULL); dst = ndisc_dst_alloc(dev, NULL, ndisc_output);
if (!dst) if (!dst)
return; return;
dst_clone(dst);
err = xfrm_lookup(&dst, &fl, NULL, 0); err = xfrm_lookup(&dst, &fl, NULL, 0);
if (err < 0) { if (err < 0) {
...@@ -664,7 +642,6 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr, ...@@ -664,7 +642,6 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
csum_partial((__u8 *) hdr, len, 0)); csum_partial((__u8 *) hdr, len, 0));
/* send it! */ /* send it! */
dst_clone(dst);
skb->dst = dst; skb->dst = dst;
idev = in6_dev_get(dst->dev); idev = in6_dev_get(dst->dev);
dst_output(skb); dst_output(skb);
...@@ -1321,7 +1298,6 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, ...@@ -1321,7 +1298,6 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
if (rt == NULL) if (rt == NULL)
return; return;
dst = &rt->u.dst; dst = &rt->u.dst;
dst_clone(dst);
err = xfrm_lookup(&dst, &fl, NULL, 0); err = xfrm_lookup(&dst, &fl, NULL, 0);
if (err) { if (err) {
...@@ -1329,16 +1305,17 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, ...@@ -1329,16 +1305,17 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
return; return;
} }
rt = (struct rt6_info *) dst;
if (rt->rt6i_flags & RTF_GATEWAY) { if (rt->rt6i_flags & RTF_GATEWAY) {
ND_PRINTK1("ndisc_send_redirect: not a neighbour\n"); ND_PRINTK1("ndisc_send_redirect: not a neighbour\n");
dst_release(&rt->u.dst); dst_release(dst);
return; return;
} }
if (!xrlim_allow(&rt->u.dst, 1*HZ)) { if (!xrlim_allow(dst, 1*HZ)) {
dst_release(&rt->u.dst); dst_release(dst);
return; return;
} }
dst_release(&rt->u.dst);
if (dev->addr_len) { if (dev->addr_len) {
if (neigh->nud_state&NUD_VALID) { if (neigh->nud_state&NUD_VALID) {
...@@ -1348,6 +1325,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, ...@@ -1348,6 +1325,7 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
We will make it later, when will be sure, We will make it later, when will be sure,
that it is alive. that it is alive.
*/ */
dst_release(dst);
return; return;
} }
} }
...@@ -1366,11 +1344,11 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, ...@@ -1366,11 +1344,11 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
hlen = 0; hlen = 0;
skb_reserve(skb, (dev->hard_header_len + 15) & ~15); skb_reserve(buff, (dev->hard_header_len + 15) & ~15);
ip6_nd_hdr(sk, buff, dev, &saddr_buf, &skb->nh.ipv6h->saddr, ip6_nd_hdr(sk, buff, dev, &saddr_buf, &skb->nh.ipv6h->saddr,
IPPROTO_ICMPV6, len); IPPROTO_ICMPV6, len);
skb->h.raw = (unsigned char*) icmph = (struct icmp6hdr *) skb_put(buff, len); buff->h.raw = (unsigned char*) icmph = (struct icmp6hdr *) skb_put(buff, len);
memset(icmph, 0, sizeof(struct icmp6hdr)); memset(icmph, 0, sizeof(struct icmp6hdr));
icmph->icmp6_type = NDISC_REDIRECT; icmph->icmp6_type = NDISC_REDIRECT;
...@@ -1408,9 +1386,9 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh, ...@@ -1408,9 +1386,9 @@ void ndisc_send_redirect(struct sk_buff *skb, struct neighbour *neigh,
len, IPPROTO_ICMPV6, len, IPPROTO_ICMPV6,
csum_partial((u8 *) icmph, len, 0)); csum_partial((u8 *) icmph, len, 0));
skb->dst = dst; buff->dst = dst;
idev = in6_dev_get(dst->dev); idev = in6_dev_get(dst->dev);
dst_output(skb); dst_output(buff);
ICMP6_INC_STATS(idev, Icmp6OutRedirects); ICMP6_INC_STATS(idev, Icmp6OutRedirects);
ICMP6_INC_STATS(idev, Icmp6OutMsgs); ICMP6_INC_STATS(idev, Icmp6OutMsgs);
......
...@@ -131,16 +131,11 @@ rwlock_t rt6_lock = RW_LOCK_UNLOCKED; ...@@ -131,16 +131,11 @@ rwlock_t rt6_lock = RW_LOCK_UNLOCKED;
/* allocate dst with ip6_dst_ops */ /* allocate dst with ip6_dst_ops */
static __inline__ struct rt6_info *__ip6_dst_alloc(void) static __inline__ struct rt6_info *ip6_dst_alloc(void)
{ {
return dst_alloc(&ip6_dst_ops); return dst_alloc(&ip6_dst_ops);
} }
struct rt6_info *ip6_dst_alloc(void)
{
return __ip6_dst_alloc();
}
/* /*
* Route lookup. Any rt6_lock is implied. * Route lookup. Any rt6_lock is implied.
*/ */
...@@ -560,6 +555,60 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu) ...@@ -560,6 +555,60 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
} }
} }
/* Protected by rt6_lock. */
static struct dst_entry *ndisc_dst_gc_list;
struct dst_entry *ndisc_dst_alloc(struct net_device *dev,
struct neighbour *neigh,
int (*output)(struct sk_buff *))
{
struct rt6_info *rt = ip6_dst_alloc();
if (unlikely(rt == NULL))
goto out;
rt->rt6i_dev = dev;
rt->rt6i_nexthop = neigh;
rt->rt6i_expires = 0;
rt->rt6i_flags = RTF_LOCAL;
rt->rt6i_metric = 0;
atomic_set(&rt->u.dst.__refcnt, 1);
rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255;
rt->u.dst.output = output;
write_lock_bh(&rt6_lock);
rt->u.dst.next = ndisc_dst_gc_list;
ndisc_dst_gc_list = &rt->u.dst;
write_unlock_bh(&rt6_lock);
fib6_force_start_gc();
out:
return (struct dst_entry *)rt;
}
int ndisc_dst_gc(int *more)
{
struct dst_entry *dst, *next, **pprev;
int freed;
next = NULL;
pprev = &ndisc_dst_gc_list;
freed = 0;
while ((dst = *pprev) != NULL) {
if (!atomic_read(&dst->__refcnt)) {
*pprev = dst->next;
dst_free(dst);
freed++;
} else {
pprev = &dst->next;
(*more)++;
}
}
return freed;
}
static int ip6_dst_gc(void) static int ip6_dst_gc(void)
{ {
static unsigned expire = 30*HZ; static unsigned expire = 30*HZ;
...@@ -655,7 +704,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr) ...@@ -655,7 +704,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr)
if (rtmsg->rtmsg_metric == 0) if (rtmsg->rtmsg_metric == 0)
rtmsg->rtmsg_metric = IP6_RT_PRIO_USER; rtmsg->rtmsg_metric = IP6_RT_PRIO_USER;
rt = __ip6_dst_alloc(); rt = ip6_dst_alloc();
if (rt == NULL) if (rt == NULL)
return -ENOMEM; return -ENOMEM;
...@@ -1066,7 +1115,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, ...@@ -1066,7 +1115,7 @@ void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr,
static struct rt6_info * ip6_rt_copy(struct rt6_info *ort) static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
{ {
struct rt6_info *rt = __ip6_dst_alloc(); struct rt6_info *rt = ip6_dst_alloc();
if (rt) { if (rt) {
rt->u.dst.input = ort->u.dst.input; rt->u.dst.input = ort->u.dst.input;
...@@ -1209,7 +1258,7 @@ int ip6_pkt_discard(struct sk_buff *skb) ...@@ -1209,7 +1258,7 @@ int ip6_pkt_discard(struct sk_buff *skb)
int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev) int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev)
{ {
struct rt6_info *rt = __ip6_dst_alloc(); struct rt6_info *rt = ip6_dst_alloc();
if (rt == NULL) if (rt == NULL)
return -ENOMEM; return -ENOMEM;
......
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