static struct rt6_info *rt6_cow(struct rt6_info *ort, struct in6_addr *daddr, struct in6_addr *saddr) { int err; struct rt6_info *rt; /* * Clone the route. */ rt = ip6_rt_copy(ort); if (rt) { ipv6_addr_copy(&rt->rt6i_dst.addr, daddr); if (!(rt->rt6i_flags&RTF_GATEWAY)) ipv6_addr_copy(&rt->rt6i_gateway, daddr); rt->rt6i_dst.plen = 128; rt->rt6i_flags |= RTF_CACHE; rt->u.dst.flags |= DST_HOST; #ifdef CONFIG_IPV6_SUBTREES if (rt->rt6i_src.plen && saddr) { ipv6_addr_copy(&rt->rt6i_src.addr, saddr); rt->rt6i_src.plen = 128; } #endif rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); dst_hold(&rt->u.dst); err = rt6_ins(rt, NULL); if (err == 0) return rt; rt->u.dst.error = err; return rt; } dst_hold(&ip6_null_entry.u.dst); return &ip6_null_entry; }
/* * Handle redirects */ void rt6_redirect(struct in6_addr *dest, struct in6_addr *saddr, struct neighbour *neigh, int on_link) { struct rt6_info *rt, *nrt; /* Locate old route to this destination. */ rt = rt6_lookup(dest, NULL, neigh->dev->ifindex, 1); if (rt == NULL) return; if (neigh->dev != rt->rt6i_dev) goto out; /* Redirect received -> path was valid. Look, redirects are sent only in response to data packets, so that this nexthop apparently is reachable. --ANK */ dst_confirm(&rt->u.dst); /* Duplicate redirect: silently ignore. */ if (neigh == rt->u.dst.neighbour) goto out; /* Current route is on-link; redirect is always invalid. Seems, previous statement is not true. It could be node, which looks for us as on-link (f.e. proxy ndisc) But then router serving it might decide, that we should know truth 8)8) --ANK (980726). */ if (!(rt->rt6i_flags&RTF_GATEWAY)) goto out; /* * RFC 1970 specifies that redirects should only be * accepted if they come from the nexthop to the target. * Due to the way default routers are chosen, this notion * is a bit fuzzy and one might need to check all default * routers. */ if (ipv6_addr_cmp(saddr, &rt->rt6i_gateway)) { if (rt->rt6i_flags & RTF_DEFAULT) { struct rt6_info *rt1; read_lock(&rt6_lock); for (rt1 = ip6_routing_table.leaf; rt1; rt1 = rt1->u.next) { if (!ipv6_addr_cmp(saddr, &rt1->rt6i_gateway)) { dst_hold(&rt1->u.dst); dst_release(&rt->u.dst); read_unlock(&rt6_lock); rt = rt1; goto source_ok; } } read_unlock(&rt6_lock); } if (net_ratelimit()) printk(KERN_DEBUG "rt6_redirect: source isn't a valid nexthop " "for redirect target\n"); goto out; } source_ok: /* * We have finally decided to accept it. */ nrt = ip6_rt_copy(rt); if (nrt == NULL) goto out; nrt->rt6i_flags = RTF_GATEWAY|RTF_UP|RTF_DYNAMIC|RTF_CACHE; if (on_link) nrt->rt6i_flags &= ~RTF_GATEWAY; ipv6_addr_copy(&nrt->rt6i_dst.addr, dest); nrt->rt6i_dst.plen = 128; nrt->u.dst.flags |= DST_HOST; ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key); nrt->rt6i_nexthop = neigh_clone(neigh); /* Reset pmtu, it may be better */ nrt->u.dst.pmtu = ipv6_get_mtu(neigh->dev); nrt->u.dst.advmss = max_t(unsigned int, nrt->u.dst.pmtu - 60, ip6_rt_min_advmss); if (rt->u.dst.advmss > 65535-20) rt->u.dst.advmss = 65535; nrt->rt6i_hoplimit = ipv6_get_hoplimit(neigh->dev); if (rt6_ins(nrt, NULL)) goto out; if (rt->rt6i_flags&RTF_CACHE) { ip6_del_rt(rt, NULL); return; } out: dst_release(&rt->u.dst); return; }
void rt6_pmtu_discovery(struct in6_addr *daddr, struct in6_addr *saddr, struct net_device *dev, u32 pmtu) { struct rt6_info *rt, *nrt; if (pmtu < IPV6_MIN_MTU) { if (net_ratelimit()) printk(KERN_DEBUG "rt6_pmtu_discovery: invalid MTU value %d\n", pmtu); /* According to RFC1981, the PMTU is set to the IPv6 minimum link MTU if the node receives a Packet Too Big message reporting next-hop MTU that is less than the IPv6 minimum MTU. */ pmtu = IPV6_MIN_MTU; } rt = rt6_lookup(daddr, saddr, dev->ifindex, 0); if (rt == NULL) return; if (pmtu >= rt->u.dst.pmtu) goto out; /* New mtu received -> path was valid. They are sent only in response to data packets, so that this nexthop apparently is reachable. --ANK */ dst_confirm(&rt->u.dst); /* Host route. If it is static, it would be better not to override it, but add new one, so that when cache entry will expire old pmtu would return automatically. */ if (rt->rt6i_flags & RTF_CACHE) { rt->u.dst.pmtu = pmtu; dst_set_expires(&rt->u.dst, ip6_rt_mtu_expires); rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES; goto out; } /* Network route. Two cases are possible: 1. It is connected route. Action: COW 2. It is gatewayed route or NONEXTHOP route. Action: clone it. */ if (!rt->rt6i_nexthop && !(rt->rt6i_flags & RTF_NONEXTHOP)) { nrt = rt6_cow(rt, daddr, saddr); if (!nrt->u.dst.error) { nrt->u.dst.pmtu = pmtu; /* According to RFC 1981, detecting PMTU increase shouldn't be happened within 5 mins, the recommended timer is 10 mins. Here this route expiration time is set to ip6_rt_mtu_expires which is 10 mins. After 10 mins the decreased pmtu is expired and detecting PMTU increase will be automatically happened. */ dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires); nrt->rt6i_flags |= RTF_DYNAMIC|RTF_EXPIRES; dst_release(&nrt->u.dst); } } else { nrt = ip6_rt_copy(rt); if (nrt == NULL) goto out; ipv6_addr_copy(&nrt->rt6i_dst.addr, daddr); nrt->rt6i_dst.plen = 128; nrt->u.dst.flags |= DST_HOST; nrt->rt6i_nexthop = neigh_clone(rt->rt6i_nexthop); dst_set_expires(&nrt->u.dst, ip6_rt_mtu_expires); nrt->rt6i_flags |= RTF_DYNAMIC|RTF_CACHE|RTF_EXPIRES; nrt->u.dst.pmtu = pmtu; rt6_ins(nrt, NULL); } out: dst_release(&rt->u.dst); }
static int ip6_fw_accept(struct dst_entry *dst, struct fl_acc_args *args) { struct rt6_info *rt; struct ip6_fw_rule *rl; int proto; int res = FLOWR_NODECISION; rt = (struct rt6_info *) dst; rl = (struct ip6_fw_rule *) rt->rt6i_flowr; proto = rl->info.proto; switch (proto) { case 0: if (rl->policy & IP6_FW_REJECT) res = FLOWR_SELECT; else res = FLOWR_CLEAR; break; case IPPROTO_TCP: case IPPROTO_UDP: res = ip6_fw_accept_trans(rl, args); break; case IPPROTO_ICMPV6: }; return res; } static struct dst_entry * ip6_fw_dup(struct dst_entry *frule, struct dst_entry *rt, struct fl_acc_args *args) { struct ip6_fw_rule *rl; struct rt6_info *nrt; struct rt6_info *frt; frt = (struct rt6_info *) frule; rl = (struct ip6_fw_rule *) frt->rt6i_flowr; nrt = ip6_rt_copy((struct rt6_info *) rt); if (nrt) { nrt->u.dst.input = frule->input; nrt->u.dst.output = frule->output; nrt->rt6i_flowr = flow_clone(frt->rt6i_flowr); nrt->rt6i_flags |= RTF_CACHE; nrt->rt6i_tstamp = jiffies; } return (struct dst_entry *) nrt; } int ip6_fw_reject(struct sk_buff *skb) { #if IP6_FW_DEBUG >= 1 printk(KERN_DEBUG "packet rejected: \n"); #endif icmpv6_send(skb, ICMPV6_DEST_UNREACH, ICMPV6_ADM_PROHIBITED, 0, skb->dev); /* * send it via netlink, as (rule, skb) */ kfree_skb(skb); return 0; }