diff options
Diffstat (limited to 'net/ipv6/route.c')
-rw-r--r-- | net/ipv6/route.c | 66 |
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 | ||
144 | static int ip6_pkt_prohibit(struct sk_buff *skb); | ||
145 | static int ip6_pkt_prohibit_out(struct sk_buff *skb); | ||
146 | static int ip6_pkt_blk_hole(struct sk_buff *skb); | ||
147 | |||
144 | struct rt6_info ip6_prohibit_entry = { | 148 | struct 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, | |||
484 | do { \ | 488 | do { \ |
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: | |||
697 | void ip6_route_input(struct sk_buff *skb) | 703 | void 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 | ||
1733 | static int ip6_pkt_discard(struct sk_buff *skb) | 1749 | static 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 | ||
1761 | static int ip6_pkt_discard(struct sk_buff *skb) | ||
1762 | { | ||
1763 | return ip6_pkt_drop(skb, ICMPV6_NOROUTE); | ||
1764 | } | ||
1765 | |||
1745 | static int ip6_pkt_discard_out(struct sk_buff *skb) | 1766 | static 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 | |||
1774 | static int ip6_pkt_prohibit(struct sk_buff *skb) | ||
1775 | { | ||
1776 | return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED); | ||
1777 | } | ||
1778 | |||
1779 | static int ip6_pkt_prohibit_out(struct sk_buff *skb) | ||
1780 | { | ||
1781 | skb->dev = skb->dst->dev; | ||
1782 | return ip6_pkt_prohibit(skb); | ||
1783 | } | ||
1784 | |||
1785 | static 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 | */ |