int ip6_rt_addr_add(struct in6_addr *addr, struct net_device *dev) { struct rt6_info *rt; rt = dst_alloc(&ip6_dst_ops); if (rt == NULL) return -ENOMEM; rt->u.dst.flags = DST_HOST; rt->u.dst.input = ip6_input; rt->u.dst.output = ip6_output; rt->rt6i_dev = dev_get_by_name("lo"); rt->u.dst.pmtu = ipv6_get_mtu(rt->rt6i_dev); rt->u.dst.advmss = max_t(unsigned int, rt->u.dst.pmtu - 60, ip6_rt_min_advmss); if (rt->u.dst.advmss > 65535-20) rt->u.dst.advmss = 65535; rt->rt6i_hoplimit = ipv6_get_hoplimit(rt->rt6i_dev); rt->u.dst.obsolete = -1; rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP; rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_gateway); if (rt->rt6i_nexthop == NULL) { dst_free((struct dst_entry *) rt); return -ENOMEM; } ipv6_addr_copy(&rt->rt6i_dst.addr, addr); rt->rt6i_dst.plen = 128; rt6_ins(rt, NULL); return 0; }
/* Route the packet according to the routing keys specified in * route_info. Keys are : * - ifindex : * 0 if no oif preferred, * otherwise set to the index of the desired oif * - route_info->gw : * 0 if no gateway specified, * otherwise set to the next host to which the pkt must be routed * If success, skb->dev is the output device to which the packet must * be sent and skb->dst is not NULL * * RETURN: 1 if the packet was succesfully routed to the * destination desired * 0 if the kernel routing table could not route the packet * according to the keys specified */ static int route6(struct sk_buff *skb, unsigned int ifindex, const struct ip6t_route_target_info *route_info) { struct rt6_info *rt = NULL; struct ipv6hdr *ipv6h = skb->nh.ipv6h; struct in6_addr *gw = (struct in6_addr*)&route_info->gw; DEBUGP("ip6t_ROUTE: called with: "); DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(ipv6h->daddr)); DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(*gw)); DEBUGP("OUT=%s\n", route_info->oif); if (ipv6_addr_any(gw)) rt = rt6_lookup(&ipv6h->daddr, &ipv6h->saddr, ifindex, 1); else rt = rt6_lookup(gw, &ipv6h->saddr, ifindex, 1); if (!rt) goto no_route; DEBUGP("ip6t_ROUTE: routing gives: "); DEBUGP("DST=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_dst.addr)); DEBUGP("GATEWAY=%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x ", NIP6(rt->rt6i_gateway)); DEBUGP("OUT=%s\n", rt->rt6i_dev->name); if (ifindex && rt->rt6i_dev->ifindex!=ifindex) goto wrong_route; if (!rt->rt6i_nexthop) { DEBUGP("ip6t_ROUTE: discovering neighbour\n"); rt->rt6i_nexthop = ndisc_get_neigh(rt->rt6i_dev, &rt->rt6i_dst.addr); } /* Drop old route. */ dst_release(skb->dst); skb->dst = &rt->u.dst; skb->dev = rt->rt6i_dev; return 1; wrong_route: dst_release(&rt->u.dst); no_route: if (!net_ratelimit()) return 0; printk("ip6t_ROUTE: no explicit route found "); if (ifindex) printk("via interface %s ", route_info->oif); if (!ipv6_addr_any(gw)) printk("via gateway %04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x", NIP6(*gw)); printk("\n"); return 0; }
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; }