aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/route.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r--net/ipv6/route.c66
1 files changed, 54 insertions, 12 deletions
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index d6b4b4f48d18..c953466b7afd 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -141,6 +141,10 @@ struct rt6_info ip6_null_entry = {
141 141
142#ifdef CONFIG_IPV6_MULTIPLE_TABLES 142#ifdef CONFIG_IPV6_MULTIPLE_TABLES
143 143
144static int ip6_pkt_prohibit(struct sk_buff *skb);
145static int ip6_pkt_prohibit_out(struct sk_buff *skb);
146static int ip6_pkt_blk_hole(struct sk_buff *skb);
147
144struct rt6_info ip6_prohibit_entry = { 148struct rt6_info ip6_prohibit_entry = {
145 .u = { 149 .u = {
146 .dst = { 150 .dst = {
@@ -150,8 +154,8 @@ struct rt6_info ip6_prohibit_entry = {
150 .obsolete = -1, 154 .obsolete = -1,
151 .error = -EACCES, 155 .error = -EACCES,
152 .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, 156 .metrics = { [RTAX_HOPLIMIT - 1] = 255, },
153 .input = ip6_pkt_discard, 157 .input = ip6_pkt_prohibit,
154 .output = ip6_pkt_discard_out, 158 .output = ip6_pkt_prohibit_out,
155 .ops = &ip6_dst_ops, 159 .ops = &ip6_dst_ops,
156 .path = (struct dst_entry*)&ip6_prohibit_entry, 160 .path = (struct dst_entry*)&ip6_prohibit_entry,
157 } 161 }
@@ -170,8 +174,8 @@ struct rt6_info ip6_blk_hole_entry = {
170 .obsolete = -1, 174 .obsolete = -1,
171 .error = -EINVAL, 175 .error = -EINVAL,
172 .metrics = { [RTAX_HOPLIMIT - 1] = 255, }, 176 .metrics = { [RTAX_HOPLIMIT - 1] = 255, },
173 .input = ip6_pkt_discard, 177 .input = ip6_pkt_blk_hole,
174 .output = ip6_pkt_discard_out, 178 .output = ip6_pkt_blk_hole,
175 .ops = &ip6_dst_ops, 179 .ops = &ip6_dst_ops,
176 .path = (struct dst_entry*)&ip6_blk_hole_entry, 180 .path = (struct dst_entry*)&ip6_blk_hole_entry,
177 } 181 }
@@ -484,7 +488,7 @@ int rt6_route_rcv(struct net_device *dev, u8 *opt, int len,
484do { \ 488do { \
485 if (rt == &ip6_null_entry) { \ 489 if (rt == &ip6_null_entry) { \
486 struct fib6_node *pn; \ 490 struct fib6_node *pn; \
487 while (fn) { \ 491 while (1) { \
488 if (fn->fn_flags & RTN_TL_ROOT) \ 492 if (fn->fn_flags & RTN_TL_ROOT) \
489 goto out; \ 493 goto out; \
490 pn = fn->parent; \ 494 pn = fn->parent; \
@@ -529,13 +533,17 @@ struct rt6_info *rt6_lookup(struct in6_addr *daddr, struct in6_addr *saddr,
529 .nl_u = { 533 .nl_u = {
530 .ip6_u = { 534 .ip6_u = {
531 .daddr = *daddr, 535 .daddr = *daddr,
532 /* TODO: saddr */
533 }, 536 },
534 }, 537 },
535 }; 538 };
536 struct dst_entry *dst; 539 struct dst_entry *dst;
537 int flags = strict ? RT6_LOOKUP_F_IFACE : 0; 540 int flags = strict ? RT6_LOOKUP_F_IFACE : 0;
538 541
542 if (saddr) {
543 memcpy(&fl.fl6_src, saddr, sizeof(*saddr));
544 flags |= RT6_LOOKUP_F_HAS_SADDR;
545 }
546
539 dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_lookup); 547 dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_lookup);
540 if (dst->error == 0) 548 if (dst->error == 0)
541 return (struct rt6_info *) dst; 549 return (struct rt6_info *) dst;
@@ -614,8 +622,6 @@ static struct rt6_info *rt6_alloc_clone(struct rt6_info *ort, struct in6_addr *d
614 ipv6_addr_copy(&rt->rt6i_dst.addr, daddr); 622 ipv6_addr_copy(&rt->rt6i_dst.addr, daddr);
615 rt->rt6i_dst.plen = 128; 623 rt->rt6i_dst.plen = 128;
616 rt->rt6i_flags |= RTF_CACHE; 624 rt->rt6i_flags |= RTF_CACHE;
617 if (rt->rt6i_flags & RTF_REJECT)
618 rt->u.dst.error = ort->u.dst.error;
619 rt->u.dst.flags |= DST_HOST; 625 rt->u.dst.flags |= DST_HOST;
620 rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop); 626 rt->rt6i_nexthop = neigh_clone(ort->rt6i_nexthop);
621 } 627 }
@@ -697,6 +703,7 @@ out2:
697void ip6_route_input(struct sk_buff *skb) 703void ip6_route_input(struct sk_buff *skb)
698{ 704{
699 struct ipv6hdr *iph = skb->nh.ipv6h; 705 struct ipv6hdr *iph = skb->nh.ipv6h;
706 int flags = RT6_LOOKUP_F_HAS_SADDR;
700 struct flowi fl = { 707 struct flowi fl = {
701 .iif = skb->dev->ifindex, 708 .iif = skb->dev->ifindex,
702 .nl_u = { 709 .nl_u = {
@@ -711,7 +718,9 @@ void ip6_route_input(struct sk_buff *skb)
711 }, 718 },
712 .proto = iph->nexthdr, 719 .proto = iph->nexthdr,
713 }; 720 };
714 int flags = rt6_need_strict(&iph->daddr) ? RT6_LOOKUP_F_IFACE : 0; 721
722 if (rt6_need_strict(&iph->daddr))
723 flags |= RT6_LOOKUP_F_IFACE;
715 724
716 skb->dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_input); 725 skb->dst = fib6_rule_lookup(&fl, flags, ip6_pol_route_input);
717} 726}
@@ -794,6 +803,9 @@ struct dst_entry * ip6_route_output(struct sock *sk, struct flowi *fl)
794 if (rt6_need_strict(&fl->fl6_dst)) 803 if (rt6_need_strict(&fl->fl6_dst))
795 flags |= RT6_LOOKUP_F_IFACE; 804 flags |= RT6_LOOKUP_F_IFACE;
796 805
806 if (!ipv6_addr_any(&fl->fl6_src))
807 flags |= RT6_LOOKUP_F_HAS_SADDR;
808
797 return fib6_rule_lookup(fl, flags, ip6_pol_route_output); 809 return fib6_rule_lookup(fl, flags, ip6_pol_route_output);
798} 810}
799 811
@@ -1345,6 +1357,7 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest,
1345 struct in6_addr *gateway, 1357 struct in6_addr *gateway,
1346 struct net_device *dev) 1358 struct net_device *dev)
1347{ 1359{
1360 int flags = RT6_LOOKUP_F_HAS_SADDR;
1348 struct ip6rd_flowi rdfl = { 1361 struct ip6rd_flowi rdfl = {
1349 .fl = { 1362 .fl = {
1350 .oif = dev->ifindex, 1363 .oif = dev->ifindex,
@@ -1357,7 +1370,9 @@ static struct rt6_info *ip6_route_redirect(struct in6_addr *dest,
1357 }, 1370 },
1358 .gateway = *gateway, 1371 .gateway = *gateway,
1359 }; 1372 };
1360 int flags = rt6_need_strict(dest) ? RT6_LOOKUP_F_IFACE : 0; 1373
1374 if (rt6_need_strict(dest))
1375 flags |= RT6_LOOKUP_F_IFACE;
1361 1376
1362 return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect); 1377 return (struct rt6_info *)fib6_rule_lookup((struct flowi *)&rdfl, flags, __ip6_route_redirect);
1363} 1378}
@@ -1527,6 +1542,7 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
1527 rt->u.dst.output = ort->u.dst.output; 1542 rt->u.dst.output = ort->u.dst.output;
1528 1543
1529 memcpy(rt->u.dst.metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32)); 1544 memcpy(rt->u.dst.metrics, ort->u.dst.metrics, RTAX_MAX*sizeof(u32));
1545 rt->u.dst.error = ort->u.dst.error;
1530 rt->u.dst.dev = ort->u.dst.dev; 1546 rt->u.dst.dev = ort->u.dst.dev;
1531 if (rt->u.dst.dev) 1547 if (rt->u.dst.dev)
1532 dev_hold(rt->u.dst.dev); 1548 dev_hold(rt->u.dst.dev);
@@ -1730,24 +1746,50 @@ int ipv6_route_ioctl(unsigned int cmd, void __user *arg)
1730 * Drop the packet on the floor 1746 * Drop the packet on the floor
1731 */ 1747 */
1732 1748
1733static int ip6_pkt_discard(struct sk_buff *skb) 1749static inline int ip6_pkt_drop(struct sk_buff *skb, int code)
1734{ 1750{
1735 int type = ipv6_addr_type(&skb->nh.ipv6h->daddr); 1751 int type = ipv6_addr_type(&skb->nh.ipv6h->daddr);
1736 if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED) 1752 if (type == IPV6_ADDR_ANY || type == IPV6_ADDR_RESERVED)
1737 IP6_INC_STATS(IPSTATS_MIB_INADDRERRORS); 1753 IP6_INC_STATS(IPSTATS_MIB_INADDRERRORS);
1738 1754
1739 IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES); 1755 IP6_INC_STATS(IPSTATS_MIB_OUTNOROUTES);
1740 icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_NOROUTE, 0, skb->dev); 1756 icmpv6_send(skb, ICMPV6_DEST_UNREACH, code, 0, skb->dev);
1741 kfree_skb(skb); 1757 kfree_skb(skb);
1742 return 0; 1758 return 0;
1743} 1759}
1744 1760
1761static int ip6_pkt_discard(struct sk_buff *skb)
1762{
1763 return ip6_pkt_drop(skb, ICMPV6_NOROUTE);
1764}
1765
1745static int ip6_pkt_discard_out(struct sk_buff *skb) 1766static int ip6_pkt_discard_out(struct sk_buff *skb)
1746{ 1767{
1747 skb->dev = skb->dst->dev; 1768 skb->dev = skb->dst->dev;
1748 return ip6_pkt_discard(skb); 1769 return ip6_pkt_discard(skb);
1749} 1770}
1750 1771
1772#ifdef CONFIG_IPV6_MULTIPLE_TABLES
1773
1774static int ip6_pkt_prohibit(struct sk_buff *skb)
1775{
1776 return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED);
1777}
1778
1779static int ip6_pkt_prohibit_out(struct sk_buff *skb)
1780{
1781 skb->dev = skb->dst->dev;
1782 return ip6_pkt_prohibit(skb);
1783}
1784
1785static int ip6_pkt_blk_hole(struct sk_buff *skb)
1786{
1787 kfree_skb(skb);
1788 return 0;
1789}
1790
1791#endif
1792
1751/* 1793/*
1752 * Allocate a dst for local (unicast / anycast) address. 1794 * Allocate a dst for local (unicast / anycast) address.
1753 */ 1795 */