* Linux INET6 implementation
*
* Authors:
- * Ville Nuorvala <vnuorval@tcs.hut.fi>
+ * Ville Nuorvala <vnuorval@tcs.hut.fi>
*
* $Id$
*
#define HASH_SIZE 32
#define HASH(addr) ((__force u32)((addr)->s6_addr32[0] ^ (addr)->s6_addr32[1] ^ \
- (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \
- (HASH_SIZE - 1))
+ (addr)->s6_addr32[2] ^ (addr)->s6_addr32[3]) & \
+ (HASH_SIZE - 1))
static int ip6ip6_fb_tnl_dev_init(struct net_device *dev);
static int ip6ip6_tnl_dev_init(struct net_device *dev);
{
struct dst_entry *dst = t->dst_cache;
- if (dst && dst->obsolete &&
+ if (dst && dst->obsolete &&
dst->ops->check(dst, t->dst_cookie) == NULL) {
t->dst_cache = NULL;
dst_release(dst);
/**
* ip6ip6_tnl_lookup - fetch tunnel matching the end-point addresses
- * @remote: the address of the tunnel exit-point
- * @local: the address of the tunnel entry-point
+ * @remote: the address of the tunnel exit-point
+ * @local: the address of the tunnel entry-point
*
- * Return:
+ * Return:
* tunnel matching given end-points if found,
- * else fallback tunnel if its device is up,
+ * else fallback tunnel if its device is up,
* else %NULL
**/
/**
* ip6ip6_bucket - get head of list matching given tunnel parameters
- * @p: parameters containing tunnel end-points
+ * @p: parameters containing tunnel end-points
*
* Description:
- * ip6ip6_bucket() returns the head of the list matching the
+ * ip6ip6_bucket() returns the head of the list matching the
* &struct in6_addr entries laddr and raddr in @p.
*
- * Return: head of IPv6 tunnel list
+ * Return: head of IPv6 tunnel list
**/
static struct ip6_tnl **
*
* Description:
* Create tunnel matching given parameters.
- *
- * Return:
+ *
+ * Return:
* created tunnel or NULL
**/
if (__dev_get_by_name(name) == NULL)
break;
}
- if (i == IP6_TNL_MAX)
+ if (i == IP6_TNL_MAX)
goto failed;
}
dev = alloc_netdev(sizeof (*t), name, ip6ip6_tnl_dev_setup);
/**
* ip6ip6_tnl_locate - find or create tunnel matching given parameters
- * @p: tunnel parameters
+ * @p: tunnel parameters
* @create: != 0 if allowed to create new tunnel if no match found
*
* Description:
/**
* ip6ip6_tnl_dev_uninit - tunnel device uninitializer
* @dev: the device to be destroyed
- *
+ *
* Description:
* ip6ip6_tnl_dev_uninit() removes tunnel from its list
**/
* parse_tvl_tnl_enc_lim - handle encapsulation limit option
* @skb: received socket buffer
*
- * Return:
- * 0 if none was found,
+ * Return:
+ * 0 if none was found,
* else index to encapsulation limit
**/
}
/**
- * ip6ip6_err - tunnel error handler
+ * ip6_tnl_err - tunnel error handler
*
* Description:
- * ip6ip6_err() should handle errors in the tunnel according
+ * ip6_tnl_err() should handle errors in the tunnel according
* to the specifications in RFC 2473.
**/
static int
-ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
- int type, int code, int offset, __be32 info)
+ip6_tnl_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ int *type, int *code, int *msg, __be32 *info, int offset)
{
struct ipv6hdr *ipv6h = (struct ipv6hdr *) skb->data;
struct ip6_tnl *t;
__u16 len;
int err = -ENOENT;
- /* If the packet doesn't contain the original IPv6 header we are
- in trouble since we might need the source address for further
+ /* If the packet doesn't contain the original IPv6 header we are
+ in trouble since we might need the source address for further
processing of the error. */
read_lock(&ip6ip6_lock);
err = 0;
- switch (type) {
+ switch (*type) {
__u32 teli;
struct ipv6_tlv_tnl_enc_lim *tel;
__u32 mtu;
rel_msg = 1;
break;
case ICMPV6_TIME_EXCEED:
- if (code == ICMPV6_EXC_HOPLIMIT) {
+ if ((*code) == ICMPV6_EXC_HOPLIMIT) {
if (net_ratelimit())
printk(KERN_WARNING
"%s: Too small hop limit or "
- "routing loop in tunnel!\n",
+ "routing loop in tunnel!\n",
t->parms.name);
rel_msg = 1;
}
break;
case ICMPV6_PARAMPROB:
teli = 0;
- if (code == ICMPV6_HDR_FIELD)
+ if ((*code) == ICMPV6_HDR_FIELD)
teli = parse_tlv_tnl_enc_lim(skb, skb->data);
- if (teli && teli == ntohl(info) - 2) {
+ if (teli && teli == ntohl(*info) - 2) {
tel = (struct ipv6_tlv_tnl_enc_lim *) &skb->data[teli];
if (tel->encap_limit == 0) {
if (net_ratelimit())
}
break;
case ICMPV6_PKT_TOOBIG:
- mtu = ntohl(info) - offset;
+ mtu = ntohl(*info) - offset;
if (mtu < IPV6_MIN_MTU)
mtu = IPV6_MIN_MTU;
t->dev->mtu = mtu;
}
break;
}
- if (rel_msg && pskb_may_pull(skb, offset + sizeof (*ipv6h))) {
+
+ *type = rel_type;
+ *code = rel_code;
+ *info = rel_info;
+ *msg = rel_msg;
+
+out:
+ read_unlock(&ip6ip6_lock);
+ return err;
+}
+
+static int
+ip6ip6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
+ int type, int code, int offset, __u32 info)
+{
+ int rel_msg = 0;
+ int rel_type = type;
+ int rel_code = code;
+ __u32 rel_info = info;
+ int err;
+
+ err = ip6_tnl_err(skb, opt, &rel_type, &rel_code, &rel_msg, &rel_info,
+ offset);
+ if (err < 0)
+ return err;
+
+ if (rel_msg && pskb_may_pull(skb, offset + sizeof(struct ipv6hdr))) {
struct rt6_info *rt;
struct sk_buff *skb2 = skb_clone(skb, GFP_ATOMIC);
if (!skb2)
- goto out;
+ return 0;
dst_release(skb2->dst);
skb2->dst = NULL;
kfree_skb(skb2);
}
-out:
- read_unlock(&ip6ip6_lock);
- return err;
+
+ return 0;
}
static inline void ip6ip6_ecn_decapsulate(struct ipv6hdr *outer_iph,
int ret = 0;
if (p->flags & IP6_TNL_F_CAP_RCV) {
- struct net_device *ldev = NULL;
+ struct net_device *ldev = NULL;
if (p->link)
ldev = dev_get_by_index(p->link);
* Return: 0
**/
-static int
+static int
ip6ip6_rcv(struct sk_buff *skb)
{
struct ipv6hdr *ipv6h;
/**
* ip6ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
* @t: the outgoing tunnel device
- * @hdr: IPv6 header from the incoming packet
+ * @hdr: IPv6 header from the incoming packet
*
* Description:
- * Avoid trivial tunneling loop by checking that tunnel exit-point
+ * Avoid trivial tunneling loop by checking that tunnel exit-point
* doesn't match source of incoming packet.
*
- * Return:
+ * Return:
* 1 if conflict,
* 0 else
**/
struct ip6_tnl_parm *p = &t->parms;
int ret = 0;
- if (p->flags & IP6_TNL_F_CAP_XMIT) {
+ if (p->flags & IP6_TNL_F_CAP_XMIT) {
struct net_device *ldev = NULL;
if (p->link)
return ret;
}
/**
- * ip6ip6_tnl_xmit - encapsulate packet and send
+ * ip6ip6_tnl_xmit - encapsulate packet and send
* @skb: the outgoing socket buffer
- * @dev: the outgoing tunnel device
+ * @dev: the outgoing tunnel device
*
* Description:
* Build new header and do some sanity checks on the packet before sending
* it.
*
- * Return:
+ * Return:
* 0
**/
-static int
+static int
ip6ip6_tnl_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct ip6_tnl *t = netdev_priv(dev);
if (tdev == dev) {
stats->collisions++;
if (net_ratelimit())
- printk(KERN_WARNING
+ printk(KERN_WARNING
"%s: Local routing loop detected!\n",
t->parms.name);
goto tx_err_dst_release;
}
if (mtu < IPV6_MIN_MTU)
mtu = IPV6_MIN_MTU;
- if (skb->dst && mtu < dst_mtu(skb->dst)) {
- struct rt6_info *rt = (struct rt6_info *) skb->dst;
- rt->rt6i_flags |= RTF_MODIFIED;
- rt->u.dst.metrics[RTAX_MTU-1] = mtu;
- }
+ if (skb->dst)
+ skb->dst->ops->update_pmtu(skb->dst, mtu);
if (skb->len > mtu) {
icmpv6_send(skb, ICMPV6_PKT_TOOBIG, 0, mtu, dev);
goto tx_err_dst_release;
* Okay, now see if we can stuff it in the buffer as-is.
*/
max_headroom += LL_RESERVED_SPACE(tdev);
-
- if (skb_headroom(skb) < max_headroom ||
+
+ if (skb_headroom(skb) < max_headroom ||
skb_cloned(skb) || skb_shared(skb)) {
struct sk_buff *new_skb;
-
+
if (!(new_skb = skb_realloc_headroom(skb, max_headroom)))
goto tx_err_dst_release;
ipv6_addr_copy(&ipv6h->daddr, &fl.fl6_dst);
nf_reset(skb);
pkt_len = skb->len;
- err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL,
+ err = NF_HOOK(PF_INET6, NF_IP6_LOCAL_OUT, skb, NULL,
skb->dst->dev, dst_output);
if (net_xmit_eval(err) == 0) {
}
/**
- * ip6ip6_tnl_ioctl - configure ipv6 tunnels from userspace
+ * ip6ip6_tnl_ioctl - configure ipv6 tunnels from userspace
* @dev: virtual device associated with tunnel
* @ifr: parameters passed from userspace
* @cmd: command to be performed
*
* Description:
- * ip6ip6_tnl_ioctl() is used for managing IPv6 tunnels
- * from userspace.
+ * ip6ip6_tnl_ioctl() is used for managing IPv6 tunnels
+ * from userspace.
*
* The possible commands are the following:
* %SIOCGETTUNNEL: get tunnel parameters for device
* %SIOCCHGTUNNEL: change tunnel parameters to those given
* %SIOCDELTUNNEL: delete tunnel
*
- * The fallback device "ip6tnl0", created during module
+ * The fallback device "ip6tnl0", created during module
* initialization, can be used for creating other tunnel devices.
*
* Return:
break;
dev = t->dev;
}
- err = unregister_netdevice(dev);
+ err = 0;
+ unregister_netdevice(dev);
break;
default:
err = -EINVAL;
}
/**
- * ip6ip6_tnl_get_stats - return the stats for tunnel device
+ * ip6ip6_tnl_get_stats - return the stats for tunnel device
* @dev: virtual device associated with tunnel
*
* Return: stats for device
* Return: 0
**/
-static int
+static int
ip6ip6_fb_tnl_dev_init(struct net_device *dev)
{
struct ip6_tnl *t = netdev_priv(dev);
{
int err;
- if (xfrm6_tunnel_register(&ip6ip6_handler)) {
+ if (xfrm6_tunnel_register(&ip6ip6_handler, AF_INET6)) {
printk(KERN_ERR "ip6ip6 init: can't register tunnel\n");
return -EAGAIN;
}
}
return 0;
fail:
- xfrm6_tunnel_deregister(&ip6ip6_handler);
+ xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6);
return err;
}
static void __exit ip6_tunnel_cleanup(void)
{
- if (xfrm6_tunnel_deregister(&ip6ip6_handler))
+ if (xfrm6_tunnel_deregister(&ip6ip6_handler, AF_INET6))
printk(KERN_INFO "ip6ip6 close: can't deregister tunnel\n");
rtnl_lock();