Release 4.11 net/xfrm/xfrm_input.c
/*
* xfrm_input.c
*
* Changes:
* YOSHIFUJI Hideaki @USAGI
* Split up af-specific portion
*
*/
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <net/dst.h>
#include <net/ip.h>
#include <net/xfrm.h>
#include <net/ip_tunnels.h>
#include <net/ip6_tunnel.h>
static struct kmem_cache *secpath_cachep __read_mostly;
static DEFINE_SPINLOCK(xfrm_input_afinfo_lock);
static struct xfrm_input_afinfo const __rcu *xfrm_input_afinfo[AF_INET6 + 1];
static struct gro_cells gro_cells;
static struct net_device xfrm_napi_dev;
int xfrm_input_register_afinfo(const struct xfrm_input_afinfo *afinfo)
{
int err = 0;
if (WARN_ON(afinfo->family >= ARRAY_SIZE(xfrm_input_afinfo)))
return -EAFNOSUPPORT;
spin_lock_bh(&xfrm_input_afinfo_lock);
if (unlikely(xfrm_input_afinfo[afinfo->family] != NULL))
err = -EEXIST;
else
rcu_assign_pointer(xfrm_input_afinfo[afinfo->family], afinfo);
spin_unlock_bh(&xfrm_input_afinfo_lock);
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Steffen Klassert | 74 | 91.36% | 1 | 33.33% |
Florian Westphal | 6 | 7.41% | 1 | 33.33% |
Li RongQing | 1 | 1.23% | 1 | 33.33% |
Total | 81 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(xfrm_input_register_afinfo);
int xfrm_input_unregister_afinfo(const struct xfrm_input_afinfo *afinfo)
{
int err = 0;
spin_lock_bh(&xfrm_input_afinfo_lock);
if (likely(xfrm_input_afinfo[afinfo->family] != NULL)) {
if (unlikely(xfrm_input_afinfo[afinfo->family] != afinfo))
err = -EINVAL;
else
RCU_INIT_POINTER(xfrm_input_afinfo[afinfo->family], NULL);
}
spin_unlock_bh(&xfrm_input_afinfo_lock);
synchronize_rcu();
return err;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Steffen Klassert | 81 | 98.78% | 1 | 50.00% |
Florian Westphal | 1 | 1.22% | 1 | 50.00% |
Total | 82 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(xfrm_input_unregister_afinfo);
static const struct xfrm_input_afinfo *xfrm_input_get_afinfo(unsigned int family)
{
const struct xfrm_input_afinfo *afinfo;
if (WARN_ON_ONCE(family >= ARRAY_SIZE(xfrm_input_afinfo)))
return NULL;
rcu_read_lock();
afinfo = rcu_dereference(xfrm_input_afinfo[family]);
if (unlikely(!afinfo))
rcu_read_unlock();
return afinfo;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Steffen Klassert | 54 | 88.52% | 1 | 50.00% |
Florian Westphal | 7 | 11.48% | 1 | 50.00% |
Total | 61 | 100.00% | 2 | 100.00% |
static int xfrm_rcv_cb(struct sk_buff *skb, unsigned int family, u8 protocol,
int err)
{
int ret;
const struct xfrm_input_afinfo *afinfo = xfrm_input_get_afinfo(family);
if (!afinfo)
return -EAFNOSUPPORT;
ret = afinfo->callback(skb, protocol, err);
rcu_read_unlock();
return ret;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Steffen Klassert | 60 | 95.24% | 1 | 50.00% |
Florian Westphal | 3 | 4.76% | 1 | 50.00% |
Total | 63 | 100.00% | 2 | 100.00% |
void __secpath_destroy(struct sec_path *sp)
{
int i;
for (i = 0; i < sp->len; i++)
xfrm_state_put(sp->xvec[i]);
kmem_cache_free(secpath_cachep, sp);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Kuznetsov | 38 | 84.44% | 1 | 33.33% |
Herbert Xu | 7 | 15.56% | 2 | 66.67% |
Total | 45 | 100.00% | 3 | 100.00% |
EXPORT_SYMBOL(__secpath_destroy);
struct sec_path *secpath_dup(struct sec_path *src)
{
struct sec_path *sp;
sp = kmem_cache_alloc(secpath_cachep, GFP_ATOMIC);
if (!sp)
return NULL;
sp->len = 0;
sp->olen = 0;
if (src) {
int i;
memcpy(sp, src, sizeof(*sp));
for (i = 0; i < sp->len; i++)
xfrm_state_hold(sp->xvec[i]);
}
atomic_set(&sp->refcnt, 1);
return sp;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 92 | 86.79% | 2 | 33.33% |
Steffen Klassert | 6 | 5.66% | 1 | 16.67% |
Alexey Kuznetsov | 5 | 4.72% | 1 | 16.67% |
Hideaki Yoshifuji / 吉藤英明 | 2 | 1.89% | 1 | 16.67% |
Christoph Lameter | 1 | 0.94% | 1 | 16.67% |
Total | 106 | 100.00% | 6 | 100.00% |
EXPORT_SYMBOL(secpath_dup);
int secpath_set(struct sk_buff *skb)
{
struct sec_path *sp;
/* Allocate new secpath or COW existing one. */
if (!skb->sp || atomic_read(&skb->sp->refcnt) != 1) {
sp = secpath_dup(skb->sp);
if (!sp)
return -ENOMEM;
if (skb->sp)
secpath_put(skb->sp);
skb->sp = sp;
}
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Steffen Klassert | 77 | 100.00% | 1 | 100.00% |
Total | 77 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(secpath_set);
/* Fetch spi and seq from ipsec header */
int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, __be32 *spi, __be32 *seq)
{
int offset, offset_seq;
int hlen;
switch (nexthdr) {
case IPPROTO_AH:
hlen = sizeof(struct ip_auth_hdr);
offset = offsetof(struct ip_auth_hdr, spi);
offset_seq = offsetof(struct ip_auth_hdr, seq_no);
break;
case IPPROTO_ESP:
hlen = sizeof(struct ip_esp_hdr);
offset = offsetof(struct ip_esp_hdr, spi);
offset_seq = offsetof(struct ip_esp_hdr, seq_no);
break;
case IPPROTO_COMP:
if (!pskb_may_pull(skb, sizeof(struct ip_comp_hdr)))
return -EINVAL;
*spi = htonl(ntohs(*(__be16 *)(skb_transport_header(skb) + 2)));
*seq = 0;
return 0;
default:
return 1;
}
if (!pskb_may_pull(skb, hlen))
return -EINVAL;
*spi = *(__be32 *)(skb_transport_header(skb) + offset);
*seq = *(__be32 *)(skb_transport_header(skb) + offset_seq);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Alexey Kuznetsov | 157 | 76.21% | 1 | 11.11% |
Herbert Xu | 20 | 9.71% | 1 | 11.11% |
Arnaldo Carvalho de Melo | 9 | 4.37% | 1 | 11.11% |
Al Viro | 5 | 2.43% | 1 | 11.11% |
James Morris | 5 | 2.43% | 1 | 11.11% |
Mitsuru Kanda | 5 | 2.43% | 1 | 11.11% |
Hideaki Yoshifuji / 吉藤英明 | 4 | 1.94% | 2 | 22.22% |
Alexey Dobriyan | 1 | 0.49% | 1 | 11.11% |
Total | 206 | 100.00% | 9 | 100.00% |
EXPORT_SYMBOL(xfrm_parse_spi);
int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
{
struct xfrm_mode *inner_mode = x->inner_mode;
int err;
err = x->outer_mode->afinfo->extract_input(x, skb);
if (err)
return err;
if (x->sel.family == AF_UNSPEC) {
inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol);
if (inner_mode == NULL)
return -EAFNOSUPPORT;
}
skb->protocol = inner_mode->afinfo->eth_proto;
return inner_mode->input2(x, skb);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 60 | 57.14% | 1 | 50.00% |
Kazunori Miyazawa | 45 | 42.86% | 1 | 50.00% |
Total | 105 | 100.00% | 2 | 100.00% |
EXPORT_SYMBOL(xfrm_prepare_input);
int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
{
struct net *net = dev_net(skb->dev);
int err;
__be32 seq;
__be32 seq_hi;
struct xfrm_state *x = NULL;
xfrm_address_t *daddr;
struct xfrm_mode *inner_mode;
u32 mark = skb->mark;
unsigned int family;
int decaps = 0;
int async = 0;
struct xfrm_offload *xo;
bool xfrm_gro = false;
if (encap_type < 0) {
x = xfrm_input_state(skb);
family = x->outer_mode->afinfo->family;
/* An encap_type of -1 indicates async resumption. */
if (encap_type == -1) {
async = 1;
seq = XFRM_SKB_CB(skb)->seq.input.low;
goto resume;
}
/* encap_type < -1 indicates a GRO call. */
encap_type = 0;
seq = XFRM_SPI_SKB_CB(skb)->seq;
goto lock;
}
daddr = (xfrm_address_t *)(skb_network_header(skb) +
XFRM_SPI_SKB_CB(skb)->daddroff);
family = XFRM_SPI_SKB_CB(skb)->family;
/* if tunnel is present override skb->mark value with tunnel i_key */
switch (family) {
case AF_INET:
if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4)
mark = be32_to_cpu(XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip4->parms.i_key);
break;
case AF_INET6:
if (XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6)
mark = be32_to_cpu(XFRM_TUNNEL_SKB_CB(skb)->tunnel.ip6->parms.i_key);
break;
}
err = secpath_set(skb);
if (err) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINERROR);
goto drop;
}
seq = 0;
if (!spi && (err = xfrm_parse_spi(skb, nexthdr, &spi, &seq)) != 0) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
goto drop;
}
do {
if (skb->sp->len == XFRM_MAX_DEPTH) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINBUFFERERROR);
goto drop;
}
x = xfrm_state_lookup(net, mark, daddr, spi, nexthdr, family);
if (x == NULL) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINNOSTATES);
xfrm_audit_state_notfound(skb, family, spi, seq);
goto drop;
}
skb->sp->xvec[skb->sp->len++] = x;
lock:
spin_lock(&x->lock);
if (unlikely(x->km.state != XFRM_STATE_VALID)) {
if (x->km.state == XFRM_STATE_ACQ)
XFRM_INC_STATS(net, LINUX_MIB_XFRMACQUIREERROR);
else
XFRM_INC_STATS(net,
LINUX_MIB_XFRMINSTATEINVALID);
goto drop_unlock;
}
if ((x->encap ? x->encap->encap_type : 0) != encap_type) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMISMATCH);
goto drop_unlock;
}
if (x->repl->check(x, skb, seq)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
goto drop_unlock;
}
if (xfrm_state_check_expire(x)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEEXPIRED);
goto drop_unlock;
}
spin_unlock(&x->lock);
if (xfrm_tunnel_check(skb, x, family)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
goto drop;
}
seq_hi = htonl(xfrm_replay_seqhi(x, seq));
XFRM_SKB_CB(skb)->seq.input.low = seq;
XFRM_SKB_CB(skb)->seq.input.hi = seq_hi;
skb_dst_force(skb);
dev_hold(skb->dev);
nexthdr = x->type->input(x, skb);
if (nexthdr == -EINPROGRESS)
return 0;
resume:
dev_put(skb->dev);
spin_lock(&x->lock);
if (nexthdr <= 0) {
if (nexthdr == -EBADMSG) {
xfrm_audit_state_icvfail(x, skb,
x->type->proto);
x->stats.integrity_failed++;
}
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEPROTOERROR);
goto drop_unlock;
}
/* only the first xfrm gets the encap type */
encap_type = 0;
if (async && x->repl->recheck(x, skb, seq)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATESEQERROR);
goto drop_unlock;
}
x->repl->advance(x, seq);
x->curlft.bytes += skb->len;
x->curlft.packets++;
spin_unlock(&x->lock);
XFRM_MODE_SKB_CB(skb)->protocol = nexthdr;
inner_mode = x->inner_mode;
if (x->sel.family == AF_UNSPEC) {
inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol);
if (inner_mode == NULL) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
goto drop;
}
}
if (inner_mode->input(x, skb)) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINSTATEMODEERROR);
goto drop;
}
if (x->outer_mode->flags & XFRM_MODE_FLAG_TUNNEL) {
decaps = 1;
break;
}
/*
* We need the inner address. However, we only get here for
* transport mode so the outer address is identical.
*/
daddr = &x->id.daddr;
family = x->outer_mode->afinfo->family;
err = xfrm_parse_spi(skb, nexthdr, &spi, &seq);
if (err < 0) {
XFRM_INC_STATS(net, LINUX_MIB_XFRMINHDRERROR);
goto drop;
}
} while (!err);
err = xfrm_rcv_cb(skb, family, x->type->proto, 0);
if (err)
goto drop;
nf_reset(skb);
if (decaps) {
skb_dst_drop(skb);
gro_cells_receive(&gro_cells, skb);
return 0;
} else {
xo = xfrm_offload(skb);
if (xo)
xfrm_gro = xo->flags & XFRM_GRO;
err = x->inner_mode->afinfo->transport_finish(skb, xfrm_gro || async);
if (xfrm_gro) {
skb_dst_drop(skb);
gro_cells_receive(&gro_cells, skb);
return err;
}
return err;
}
drop_unlock:
spin_unlock(&x->lock);
drop:
xfrm_rcv_cb(skb, family, x && x->type ? x->type->proto : nexthdr, -1);
kfree_skb(skb);
return 0;
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 496 | 45.30% | 10 | 26.32% |
Steffen Klassert | 267 | 24.38% | 11 | 28.95% |
Masahide Nakamura | 67 | 6.12% | 2 | 5.26% |
Alexander Duyck | 61 | 5.57% | 1 | 2.63% |
Alexey Dobriyan | 57 | 5.21% | 4 | 10.53% |
Kazunori Miyazawa | 44 | 4.02% | 1 | 2.63% |
David S. Miller | 30 | 2.74% | 1 | 2.63% |
Alexey Kodanev | 19 | 1.74% | 1 | 2.63% |
Subash Abhinov Kasiviswanathan | 14 | 1.28% | 1 | 2.63% |
Paul Moore | 13 | 1.19% | 1 | 2.63% |
Li RongQing | 12 | 1.10% | 1 | 2.63% |
Fan Du | 10 | 0.91% | 1 | 2.63% |
Jamal Hadi Salim | 2 | 0.18% | 1 | 2.63% |
Sabrina Dubroca | 2 | 0.18% | 1 | 2.63% |
Eric Dumazet | 1 | 0.09% | 1 | 2.63% |
Total | 1095 | 100.00% | 38 | 100.00% |
EXPORT_SYMBOL(xfrm_input);
int xfrm_input_resume(struct sk_buff *skb, int nexthdr)
{
return xfrm_input(skb, nexthdr, 0, -1);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 26 | 100.00% | 1 | 100.00% |
Total | 26 | 100.00% | 1 | 100.00% |
EXPORT_SYMBOL(xfrm_input_resume);
void __init xfrm_input_init(void)
{
int err;
init_dummy_netdev(&xfrm_napi_dev);
err = gro_cells_init(&gro_cells, &xfrm_napi_dev);
if (err)
gro_cells.cells = NULL;
secpath_cachep = kmem_cache_create("secpath_cache",
sizeof(struct sec_path),
0, SLAB_HWCACHE_ALIGN|SLAB_PANIC,
NULL);
}
Contributors
Person | Tokens | Prop | Commits | CommitProp |
Steffen Klassert | 30 | 50.85% | 1 | 33.33% |
Herbert Xu | 27 | 45.76% | 1 | 33.33% |
Alexey Dobriyan | 2 | 3.39% | 1 | 33.33% |
Total | 59 | 100.00% | 3 | 100.00% |
Overall Contributors
Person | Tokens | Prop | Commits | CommitProp |
Herbert Xu | 756 | 35.78% | 14 | 22.58% |
Steffen Klassert | 694 | 32.84% | 14 | 22.58% |
Alexey Kuznetsov | 206 | 9.75% | 1 | 1.61% |
Kazunori Miyazawa | 89 | 4.21% | 1 | 1.61% |
Masahide Nakamura | 67 | 3.17% | 2 | 3.23% |
Alexander Duyck | 67 | 3.17% | 1 | 1.61% |
Alexey Dobriyan | 60 | 2.84% | 6 | 9.68% |
David S. Miller | 30 | 1.42% | 1 | 1.61% |
Florian Westphal | 21 | 0.99% | 1 | 1.61% |
Alexey Kodanev | 19 | 0.90% | 1 | 1.61% |
Subash Abhinov Kasiviswanathan | 14 | 0.66% | 1 | 1.61% |
Li RongQing | 13 | 0.62% | 2 | 3.23% |
Paul Moore | 13 | 0.62% | 1 | 1.61% |
Adrian Bunk | 13 | 0.62% | 1 | 1.61% |
Fan Du | 10 | 0.47% | 1 | 1.61% |
Arnaldo Carvalho de Melo | 9 | 0.43% | 1 | 1.61% |
Hideaki Yoshifuji / 吉藤英明 | 8 | 0.38% | 4 | 6.45% |
James Morris | 5 | 0.24% | 1 | 1.61% |
Mitsuru Kanda | 5 | 0.24% | 1 | 1.61% |
Al Viro | 5 | 0.24% | 1 | 1.61% |
Christoph Lameter | 3 | 0.14% | 2 | 3.23% |
Eric Dumazet | 2 | 0.09% | 2 | 3.23% |
Jamal Hadi Salim | 2 | 0.09% | 1 | 1.61% |
Sabrina Dubroca | 2 | 0.09% | 1 | 1.61% |
Total | 2113 | 100.00% | 62 | 100.00% |
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.