Commit a52dca4e authored by Kazunori Miyazawa's avatar Kazunori Miyazawa Committed by Hideaki Yoshifuji

[IPV6]: Unify ipv6 output routine.

parent 8fcb1257
......@@ -24,7 +24,6 @@
#define RTF_CACHE 0x01000000 /* cache entry */
#define RTF_FLOW 0x02000000 /* flow significant route */
#define RTF_POLICY 0x04000000 /* policy route */
#define RTF_NDISC 0x08000000 /* ndisc route */
#define RTF_LOCAL 0x80000000
......
......@@ -64,6 +64,7 @@ extern struct rt6_info *rt6_lookup(struct in6_addr *daddr,
extern struct dst_entry *ndisc_dst_alloc(struct net_device *dev,
struct neighbour *neigh,
struct in6_addr *addr,
int (*output)(struct sk_buff *));
extern int ndisc_dst_gc(int *more);
extern void fib6_force_start_gc(void);
......
......@@ -355,6 +355,7 @@ extern int ip6_dst_lookup(struct sock *sk,
*/
extern int ip6_output(struct sk_buff *skb);
extern int ip6_output2(struct sk_buff *skb);
extern int ip6_forward(struct sk_buff *skb);
extern int ip6_input(struct sk_buff *skb);
extern int ip6_mc_input(struct sk_buff *skb);
......
......@@ -341,65 +341,10 @@ static void pndisc_destructor(struct pneigh_entry *n)
ipv6_dev_mc_dec(dev, &maddr);
}
static int
ndisc_build_ll_hdr(struct sk_buff *skb, struct net_device *dev,
struct in6_addr *daddr, struct neighbour *neigh, int len)
{
unsigned char ha[MAX_ADDR_LEN];
unsigned char *h_dest = NULL;
if (dev->hard_header) {
if (ipv6_addr_is_multicast(daddr)) {
ndisc_mc_map(daddr, ha, dev, 1);
h_dest = ha;
} else if (neigh) {
read_lock_bh(&neigh->lock);
if (neigh->nud_state&NUD_VALID) {
memcpy(ha, neigh->ha, dev->addr_len);
h_dest = ha;
}
read_unlock_bh(&neigh->lock);
} else {
neigh = neigh_lookup(&nd_tbl, daddr, dev);
if (neigh) {
read_lock_bh(&neigh->lock);
if (neigh->nud_state&NUD_VALID) {
memcpy(ha, neigh->ha, dev->addr_len);
h_dest = ha;
}
read_unlock_bh(&neigh->lock);
neigh_release(neigh);
}
}
if (dev->hard_header(skb, dev, ETH_P_IPV6, h_dest, NULL, len) < 0)
return 0;
}
return 1;
}
/*
* Send a Neighbour Advertisement
*/
static int ndisc_output(struct sk_buff *skb)
{
if (skb) {
struct neighbour *neigh = (skb->dst ? skb->dst->neighbour : NULL);
if (ndisc_build_ll_hdr(skb, skb->dev, &skb->nh.ipv6h->daddr, neigh, skb->len) == 0) {
kfree_skb(skb);
return -EINVAL;
}
dev_queue_xmit(skb);
return 0;
}
return -EINVAL;
}
static inline void ndisc_flow_init(struct flowi *fl, u8 type,
struct in6_addr *saddr, struct in6_addr *daddr)
{
......@@ -442,7 +387,7 @@ static void ndisc_send_na(struct net_device *dev, struct neighbour *neigh,
ndisc_flow_init(&fl, NDISC_NEIGHBOUR_ADVERTISEMENT, src_addr, daddr);
dst = ndisc_dst_alloc(dev, neigh, ndisc_output);
dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output2);
if (!dst)
return;
......@@ -530,7 +475,7 @@ void ndisc_send_ns(struct net_device *dev, struct neighbour *neigh,
ndisc_flow_init(&fl, NDISC_NEIGHBOUR_SOLICITATION, saddr, daddr);
dst = ndisc_dst_alloc(dev, neigh, ndisc_output);
dst = ndisc_dst_alloc(dev, neigh, daddr, ip6_output2);
if (!dst)
return;
......@@ -603,7 +548,7 @@ void ndisc_send_rs(struct net_device *dev, struct in6_addr *saddr,
ndisc_flow_init(&fl, NDISC_ROUTER_SOLICITATION, saddr, daddr);
dst = ndisc_dst_alloc(dev, NULL, ndisc_output);
dst = ndisc_dst_alloc(dev, NULL, daddr, ip6_output2);
if (!dst)
return;
......
......@@ -563,6 +563,7 @@ static struct dst_entry *ndisc_dst_gc_list;
struct dst_entry *ndisc_dst_alloc(struct net_device *dev,
struct neighbour *neigh,
struct in6_addr *addr,
int (*output)(struct sk_buff *))
{
struct rt6_info *rt = ip6_dst_alloc();
......@@ -574,11 +575,13 @@ struct dst_entry *ndisc_dst_alloc(struct net_device *dev,
dev_hold(dev);
if (neigh)
neigh_hold(neigh);
else
neigh = ndisc_get_neigh(dev, addr);
rt->rt6i_dev = dev;
rt->rt6i_nexthop = neigh;
rt->rt6i_expires = 0;
rt->rt6i_flags = RTF_LOCAL | RTF_NDISC;
rt->rt6i_flags = RTF_LOCAL;
rt->rt6i_metric = 0;
atomic_set(&rt->u.dst.__refcnt, 1);
rt->u.dst.metrics[RTAX_HOPLIMIT-1] = 255;
......@@ -832,7 +835,7 @@ int ip6_route_add(struct in6_rtmsg *rtmsg, struct nlmsghdr *nlh, void *_rtattr)
}
}
rt->rt6i_flags = rtmsg->rtmsg_flags & ~RTF_NDISC;
rt->rt6i_flags = rtmsg->rtmsg_flags;
install_route:
if (rta && rta[RTA_METRICS-1]) {
......@@ -1125,8 +1128,6 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
{
struct rt6_info *rt = ip6_dst_alloc();
BUG_ON(ort->rt6i_flags & RTF_NDISC);
if (rt) {
rt->u.dst.input = ort->u.dst.input;
rt->u.dst.output = ort->u.dst.output;
......
......@@ -55,13 +55,6 @@ static struct dst_entry *
__xfrm6_find_bundle(struct flowi *fl, struct rtable *rt, struct xfrm_policy *policy)
{
struct dst_entry *dst;
u32 ndisc_bit = 0;
if (fl->proto == IPPROTO_ICMPV6 &&
(fl->fl_icmp_type == NDISC_NEIGHBOUR_ADVERTISEMENT ||
fl->fl_icmp_type == NDISC_NEIGHBOUR_SOLICITATION ||
fl->fl_icmp_type == NDISC_ROUTER_SOLICITATION))
ndisc_bit = RTF_NDISC;
/* Still not clear if we should set fl->fl6_{src,dst}... */
read_lock_bh(&policy->lock);
......@@ -69,9 +62,6 @@ __xfrm6_find_bundle(struct flowi *fl, struct rtable *rt, struct xfrm_policy *pol
struct xfrm_dst *xdst = (struct xfrm_dst*)dst;
struct in6_addr fl_dst_prefix, fl_src_prefix;
if ((xdst->u.rt6.rt6i_flags & RTF_NDISC) != ndisc_bit)
continue;
ipv6_addr_prefix(&fl_dst_prefix,
&fl->fl6_dst,
xdst->u.rt6.rt6i_dst.plen);
......@@ -169,7 +159,7 @@ __xfrm6_bundle_create(struct xfrm_policy *policy, struct xfrm_state **xfrm, int
dst_prev->output = dst_prev->xfrm->type->output;
/* Sheit... I remember I did this right. Apparently,
* it was magically lost, so this code needs audit */
x->u.rt6.rt6i_flags = rt0->rt6i_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL|RTF_NDISC);
x->u.rt6.rt6i_flags = rt0->rt6i_flags&(RTCF_BROADCAST|RTCF_MULTICAST|RTCF_LOCAL);
x->u.rt6.rt6i_metric = rt0->rt6i_metric;
x->u.rt6.rt6i_node = rt0->rt6i_node;
x->u.rt6.rt6i_gateway = rt0->rt6i_gateway;
......
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