cregit-Linux how code gets into the kernel

Release 4.8 net/ipv6/xfrm6_tunnel.c

Directory: net/ipv6
/*
 * Copyright (C)2003,2004 USAGI/WIDE Project
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 *
 * Authors      Mitsuru KANDA  <mk@linux-ipv6.org>
 *              YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
 *
 * Based on net/ipv4/xfrm4_tunnel.c
 *
 */
#include <linux/module.h>
#include <linux/xfrm.h>
#include <linux/slab.h>
#include <linux/rculist.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/ipv6.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include <linux/mutex.h>
#include <net/netns/generic.h>


#define XFRM6_TUNNEL_SPI_BYADDR_HSIZE 256

#define XFRM6_TUNNEL_SPI_BYSPI_HSIZE 256


#define XFRM6_TUNNEL_SPI_MIN	1

#define XFRM6_TUNNEL_SPI_MAX	0xffffffff


struct xfrm6_tunnel_net {
	
struct hlist_head spi_byaddr[XFRM6_TUNNEL_SPI_BYADDR_HSIZE];
	
struct hlist_head spi_byspi[XFRM6_TUNNEL_SPI_BYSPI_HSIZE];
	
u32 spi;
};


static int xfrm6_tunnel_net_id __read_mostly;

static inline struct xfrm6_tunnel_net *xfrm6_tunnel_pernet(struct net *net) { return net_generic(net, xfrm6_tunnel_net_id); }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan22100.00%1100.00%
Total22100.00%1100.00%

/* * xfrm_tunnel_spi things are for allocating unique id ("spi") * per xfrm_address_t. */ struct xfrm6_tunnel_spi { struct hlist_node list_byaddr; struct hlist_node list_byspi; xfrm_address_t addr; u32 spi; atomic_t refcnt; struct rcu_head rcu_head; }; static DEFINE_SPINLOCK(xfrm6_tunnel_spi_lock); static struct kmem_cache *xfrm6_tunnel_spi_kmem __read_mostly;
static inline unsigned int xfrm6_tunnel_spi_hash_byaddr(const xfrm_address_t *addr) { unsigned int h; h = ipv6_addr_hash((const struct in6_addr *)addr); h ^= h >> 16; h ^= h >> 8; h &= XFRM6_TUNNEL_SPI_BYADDR_HSIZE - 1; return h; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji4588.24%233.33%
eric dumazeteric dumazet35.88%233.33%
al viroal viro23.92%116.67%
dave jonesdave jones11.96%116.67%
Total51100.00%6100.00%


static inline unsigned int xfrm6_tunnel_spi_hash_byspi(u32 spi) { return spi % XFRM6_TUNNEL_SPI_BYSPI_HSIZE; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji1487.50%133.33%
dave jonesdave jones16.25%133.33%
eric dumazeteric dumazet16.25%133.33%
Total16100.00%3100.00%


static struct xfrm6_tunnel_spi *__xfrm6_tunnel_spi_lookup(struct net *net, const xfrm_address_t *saddr) { struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); struct xfrm6_tunnel_spi *x6spi; hlist_for_each_entry_rcu(x6spi, &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], list_byaddr) { if (xfrm6_addr_equal(&x6spi->addr, saddr)) return x6spi; } return NULL; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji4370.49%240.00%
alexey dobriyanalexey dobriyan1626.23%120.00%
eric dumazeteric dumazet23.28%240.00%
Total61100.00%5100.00%


__be32 xfrm6_tunnel_spi_lookup(struct net *net, const xfrm_address_t *saddr) { struct xfrm6_tunnel_spi *x6spi; u32 spi; rcu_read_lock_bh(); x6spi = __xfrm6_tunnel_spi_lookup(net, saddr); spi = x6spi ? x6spi->spi : 0; rcu_read_unlock_bh(); return htonl(spi); }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji3870.37%116.67%
alexey dobriyanalexey dobriyan712.96%116.67%
eric dumazeteric dumazet59.26%233.33%
al viroal viro47.41%233.33%
Total54100.00%6100.00%

EXPORT_SYMBOL(xfrm6_tunnel_spi_lookup);
static int __xfrm6_tunnel_spi_check(struct net *net, u32 spi) { struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); struct xfrm6_tunnel_spi *x6spi; int index = xfrm6_tunnel_spi_hash_byspi(spi); hlist_for_each_entry(x6spi, &xfrm6_tn->spi_byspi[index], list_byspi) { if (x6spi->spi == spi) return -1; } return index; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji4674.19%150.00%
alexey dobriyanalexey dobriyan1625.81%150.00%
Total62100.00%2100.00%


static u32 __xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr) { struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); u32 spi; struct xfrm6_tunnel_spi *x6spi; int index; if (xfrm6_tn->spi < XFRM6_TUNNEL_SPI_MIN || xfrm6_tn->spi >= XFRM6_TUNNEL_SPI_MAX) xfrm6_tn->spi = XFRM6_TUNNEL_SPI_MIN; else xfrm6_tn->spi++; for (spi = xfrm6_tn->spi; spi <= XFRM6_TUNNEL_SPI_MAX; spi++) { index = __xfrm6_tunnel_spi_check(net, spi); if (index >= 0) goto alloc_spi; } for (spi = XFRM6_TUNNEL_SPI_MIN; spi < xfrm6_tn->spi; spi++) { index = __xfrm6_tunnel_spi_check(net, spi); if (index >= 0) goto alloc_spi; } spi = 0; goto out; alloc_spi: xfrm6_tn->spi = spi; x6spi = kmem_cache_alloc(xfrm6_tunnel_spi_kmem, GFP_ATOMIC); if (!x6spi) goto out; memcpy(&x6spi->addr, saddr, sizeof(x6spi->addr)); x6spi->spi = spi; atomic_set(&x6spi->refcnt, 1); hlist_add_head_rcu(&x6spi->list_byspi, &xfrm6_tn->spi_byspi[index]); index = xfrm6_tunnel_spi_hash_byaddr(saddr); hlist_add_head_rcu(&x6spi->list_byaddr, &xfrm6_tn->spi_byaddr[index]); out: return spi; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji19279.67%240.00%
alexey dobriyanalexey dobriyan4619.09%120.00%
eric dumazeteric dumazet20.83%120.00%
christoph lameterchristoph lameter10.41%120.00%
Total241100.00%5100.00%


__be32 xfrm6_tunnel_alloc_spi(struct net *net, xfrm_address_t *saddr) { struct xfrm6_tunnel_spi *x6spi; u32 spi; spin_lock_bh(&xfrm6_tunnel_spi_lock); x6spi = __xfrm6_tunnel_spi_lookup(net, saddr); if (x6spi) { atomic_inc(&x6spi->refcnt); spi = x6spi->spi; } else spi = __xfrm6_tunnel_alloc_spi(net, saddr); spin_unlock_bh(&xfrm6_tunnel_spi_lock); return htonl(spi); }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji6481.01%120.00%
alexey dobriyanalexey dobriyan911.39%120.00%
al viroal viro45.06%240.00%
eric dumazeteric dumazet22.53%120.00%
Total79100.00%5100.00%

EXPORT_SYMBOL(xfrm6_tunnel_alloc_spi);
static void x6spi_destroy_rcu(struct rcu_head *head) { kmem_cache_free(xfrm6_tunnel_spi_kmem, container_of(head, struct xfrm6_tunnel_spi, rcu_head)); }

Contributors

PersonTokensPropCommitsCommitProp
eric dumazeteric dumazet26100.00%1100.00%
Total26100.00%1100.00%


static void xfrm6_tunnel_free_spi(struct net *net, xfrm_address_t *saddr) { struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); struct xfrm6_tunnel_spi *x6spi; struct hlist_node *n; spin_lock_bh(&xfrm6_tunnel_spi_lock); hlist_for_each_entry_safe(x6spi, n, &xfrm6_tn->spi_byaddr[xfrm6_tunnel_spi_hash_byaddr(saddr)], list_byaddr) { if (xfrm6_addr_equal(&x6spi->addr, saddr)) { if (atomic_dec_and_test(&x6spi->refcnt)) { hlist_del_rcu(&x6spi->list_byaddr); hlist_del_rcu(&x6spi->list_byspi); call_rcu(&x6spi->rcu_head, x6spi_destroy_rcu); break; } } } spin_unlock_bh(&xfrm6_tunnel_spi_lock); }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji8575.89%240.00%
alexey dobriyanalexey dobriyan1614.29%120.00%
eric dumazeteric dumazet108.93%120.00%
stephen hemmingerstephen hemminger10.89%120.00%
Total112100.00%5100.00%


static int xfrm6_tunnel_output(struct xfrm_state *x, struct sk_buff *skb) { skb_push(skb, -skb_network_offset(skb)); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
herbert xuherbert xu1860.00%480.00%
hideaki yoshifujihideaki yoshifuji1240.00%120.00%
Total30100.00%5100.00%


static int xfrm6_tunnel_input(struct xfrm_state *x, struct sk_buff *skb) { return skb_network_header(skb)[IP6CB(skb)->nhoff]; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji1860.00%150.00%
herbert xuherbert xu1240.00%150.00%
Total30100.00%2100.00%


static int xfrm6_tunnel_rcv(struct sk_buff *skb) { struct net *net = dev_net(skb->dev); const struct ipv6hdr *iph = ipv6_hdr(skb); __be32 spi; spi = xfrm6_tunnel_spi_lookup(net, (const xfrm_address_t *)&iph->saddr); return xfrm6_rcv_spi(skb, IPPROTO_IPV6, spi, NULL); }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji3756.06%111.11%
alexey dobriyanalexey dobriyan1421.21%111.11%
herbert xuherbert xu710.61%333.33%
arnaldo carvalho de meloarnaldo carvalho de melo34.55%111.11%
nicolas dichtelnicolas dichtel23.03%111.11%
eric dumazeteric dumazet23.03%111.11%
al viroal viro11.52%111.11%
Total66100.00%9100.00%


static int xfrm6_tunnel_err(struct sk_buff *skb, struct inet6_skb_parm *opt, u8 type, u8 code, int offset, __be32 info) { /* xfrm6_tunnel native err handling */ switch (type) { case ICMPV6_DEST_UNREACH: switch (code) { case ICMPV6_NOROUTE: case ICMPV6_ADM_PROHIBITED: case ICMPV6_NOT_NEIGHBOUR: case ICMPV6_ADDR_UNREACH: case ICMPV6_PORT_UNREACH: default: break; } break; case ICMPV6_PKT_TOOBIG: break; case ICMPV6_TIME_EXCEED: switch (code) { case ICMPV6_EXC_HOPLIMIT: break; case ICMPV6_EXC_FRAGTIME: default: break; } break; case ICMPV6_PARAMPROB: switch (code) { case ICMPV6_HDR_FIELD: break; case ICMPV6_UNK_NEXTHDR: break; case ICMPV6_UNK_OPTION: break; } break; default: break; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji10593.75%125.00%
herbert xuherbert xu43.57%125.00%
brian haleybrian haley21.79%125.00%
al viroal viro10.89%125.00%
Total112100.00%4100.00%


static int xfrm6_tunnel_init_state(struct xfrm_state *x) { if (x->props.mode != XFRM_MODE_TUNNEL) return -EINVAL; if (x->encap) return -EINVAL; x->props.header_len = sizeof(struct ipv6hdr); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji3876.00%133.33%
herbert xuherbert xu1020.00%133.33%
masahide nakamuramasahide nakamura24.00%133.33%
Total50100.00%3100.00%


static void xfrm6_tunnel_destroy(struct xfrm_state *x) { struct net *net = xs_net(x); xfrm6_tunnel_free_spi(net, (xfrm_address_t *)&x->props.saddr); }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji2567.57%150.00%
alexey dobriyanalexey dobriyan1232.43%150.00%
Total37100.00%2100.00%

static const struct xfrm_type xfrm6_tunnel_type = { .description = "IP6IP6", .owner = THIS_MODULE, .proto = IPPROTO_IPV6, .init_state = xfrm6_tunnel_init_state, .destructor = xfrm6_tunnel_destroy, .input = xfrm6_tunnel_input, .output = xfrm6_tunnel_output, }; static struct xfrm6_tunnel xfrm6_tunnel_handler __read_mostly = { .handler = xfrm6_tunnel_rcv, .err_handler = xfrm6_tunnel_err, .priority = 2, }; static struct xfrm6_tunnel xfrm46_tunnel_handler __read_mostly = { .handler = xfrm6_tunnel_rcv, .err_handler = xfrm6_tunnel_err, .priority = 2, };
static int __net_init xfrm6_tunnel_net_init(struct net *net) { struct xfrm6_tunnel_net *xfrm6_tn = xfrm6_tunnel_pernet(net); unsigned int i; for (i = 0; i < XFRM6_TUNNEL_SPI_BYADDR_HSIZE; i++) INIT_HLIST_HEAD(&xfrm6_tn->spi_byaddr[i]); for (i = 0; i < XFRM6_TUNNEL_SPI_BYSPI_HSIZE; i++) INIT_HLIST_HEAD(&xfrm6_tn->spi_byspi[i]); xfrm6_tn->spi = 0; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan83100.00%1100.00%
Total83100.00%1100.00%


static void __net_exit xfrm6_tunnel_net_exit(struct net *net) { }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan11100.00%1100.00%
Total11100.00%1100.00%

static struct pernet_operations xfrm6_tunnel_net_ops = { .init = xfrm6_tunnel_net_init, .exit = xfrm6_tunnel_net_exit, .id = &xfrm6_tunnel_net_id, .size = sizeof(struct xfrm6_tunnel_net), };
static int __init xfrm6_tunnel_init(void) { int rv; xfrm6_tunnel_spi_kmem = kmem_cache_create("xfrm6_tunnel_spi", sizeof(struct xfrm6_tunnel_spi), 0, SLAB_HWCACHE_ALIGN, NULL); if (!xfrm6_tunnel_spi_kmem) return -ENOMEM; rv = register_pernet_subsys(&xfrm6_tunnel_net_ops); if (rv < 0) goto out_pernet; rv = xfrm_register_type(&xfrm6_tunnel_type, AF_INET6); if (rv < 0) goto out_type; rv = xfrm6_tunnel_register(&xfrm6_tunnel_handler, AF_INET6); if (rv < 0) goto out_xfrm6; rv = xfrm6_tunnel_register(&xfrm46_tunnel_handler, AF_INET); if (rv < 0) goto out_xfrm46; return 0; out_xfrm46: xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); out_xfrm6: xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); out_type: unregister_pernet_subsys(&xfrm6_tunnel_net_ops); out_pernet: kmem_cache_destroy(xfrm6_tunnel_spi_kmem); return rv; }

Contributors

PersonTokensPropCommitsCommitProp
alexey dobriyanalexey dobriyan9963.87%337.50%
hideaki yoshifujihideaki yoshifuji2616.77%112.50%
ilpo jarvinenilpo jarvinen138.39%112.50%
kazunori miyazawakazunori miyazawa127.74%112.50%
herbert xuherbert xu53.23%225.00%
Total155100.00%8100.00%


static void __exit xfrm6_tunnel_fini(void) { xfrm6_tunnel_deregister(&xfrm46_tunnel_handler, AF_INET); xfrm6_tunnel_deregister(&xfrm6_tunnel_handler, AF_INET6); xfrm_unregister_type(&xfrm6_tunnel_type, AF_INET6); unregister_pernet_subsys(&xfrm6_tunnel_net_ops); kmem_cache_destroy(xfrm6_tunnel_spi_kmem); }

Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji2045.45%120.00%
alexey dobriyanalexey dobriyan1125.00%120.00%
kazunori miyazawakazunori miyazawa1022.73%120.00%
herbert xuherbert xu36.82%240.00%
Total44100.00%5100.00%

module_init(xfrm6_tunnel_init); module_exit(xfrm6_tunnel_fini); MODULE_LICENSE("GPL"); MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_IPV6);

Overall Contributors

PersonTokensPropCommitsCommitProp
hideaki yoshifujihideaki yoshifuji91957.01%511.11%
alexey dobriyanalexey dobriyan44027.30%36.67%
herbert xuherbert xu794.90%1124.44%
eric dumazeteric dumazet633.91%613.33%
kazunori miyazawakazunori miyazawa442.73%12.22%
ilpo jarvinenilpo jarvinen130.81%12.22%
al viroal viro120.74%48.89%
david s. millerdavid s. miller100.62%12.22%
masahide nakamuramasahide nakamura90.56%24.44%
arnaldo carvalho de meloarnaldo carvalho de melo30.19%12.22%
arjan van de venarjan van de ven30.19%12.22%
tejun heotejun heo30.19%12.22%
thomas gleixnerthomas gleixner30.19%12.22%
christoph lameterchristoph lameter30.19%24.44%
dave jonesdave jones20.12%12.22%
nicolas dichtelnicolas dichtel20.12%12.22%
brian haleybrian haley20.12%12.22%
ian morrisian morris10.06%12.22%
stephen hemmingerstephen hemminger10.06%12.22%
Total1612100.00%45100.00%
Directory: net/ipv6
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.