cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

ah6.c (18169B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * Copyright (C)2002 USAGI/WIDE Project
      4 *
      5 * Authors
      6 *
      7 *	Mitsuru KANDA @USAGI       : IPv6 Support
      8 *	Kazunori MIYAZAWA @USAGI   :
      9 *	Kunihiro Ishiguro <kunihiro@ipinfusion.com>
     10 *
     11 *	This file is derived from net/ipv4/ah.c.
     12 */
     13
     14#define pr_fmt(fmt) "IPv6: " fmt
     15
     16#include <crypto/algapi.h>
     17#include <crypto/hash.h>
     18#include <linux/module.h>
     19#include <linux/slab.h>
     20#include <net/ip.h>
     21#include <net/ah.h>
     22#include <linux/crypto.h>
     23#include <linux/pfkeyv2.h>
     24#include <linux/string.h>
     25#include <linux/scatterlist.h>
     26#include <net/ip6_route.h>
     27#include <net/icmp.h>
     28#include <net/ipv6.h>
     29#include <net/protocol.h>
     30#include <net/xfrm.h>
     31
     32#define IPV6HDR_BASELEN 8
     33
     34struct tmp_ext {
     35#if IS_ENABLED(CONFIG_IPV6_MIP6)
     36		struct in6_addr saddr;
     37#endif
     38		struct in6_addr daddr;
     39		char hdrs[];
     40};
     41
     42struct ah_skb_cb {
     43	struct xfrm_skb_cb xfrm;
     44	void *tmp;
     45};
     46
     47#define AH_SKB_CB(__skb) ((struct ah_skb_cb *)&((__skb)->cb[0]))
     48
     49static void *ah_alloc_tmp(struct crypto_ahash *ahash, int nfrags,
     50			  unsigned int size)
     51{
     52	unsigned int len;
     53
     54	len = size + crypto_ahash_digestsize(ahash) +
     55	      (crypto_ahash_alignmask(ahash) &
     56	       ~(crypto_tfm_ctx_alignment() - 1));
     57
     58	len = ALIGN(len, crypto_tfm_ctx_alignment());
     59
     60	len += sizeof(struct ahash_request) + crypto_ahash_reqsize(ahash);
     61	len = ALIGN(len, __alignof__(struct scatterlist));
     62
     63	len += sizeof(struct scatterlist) * nfrags;
     64
     65	return kmalloc(len, GFP_ATOMIC);
     66}
     67
     68static inline struct tmp_ext *ah_tmp_ext(void *base)
     69{
     70	return base + IPV6HDR_BASELEN;
     71}
     72
     73static inline u8 *ah_tmp_auth(u8 *tmp, unsigned int offset)
     74{
     75	return tmp + offset;
     76}
     77
     78static inline u8 *ah_tmp_icv(struct crypto_ahash *ahash, void *tmp,
     79			     unsigned int offset)
     80{
     81	return PTR_ALIGN((u8 *)tmp + offset, crypto_ahash_alignmask(ahash) + 1);
     82}
     83
     84static inline struct ahash_request *ah_tmp_req(struct crypto_ahash *ahash,
     85					       u8 *icv)
     86{
     87	struct ahash_request *req;
     88
     89	req = (void *)PTR_ALIGN(icv + crypto_ahash_digestsize(ahash),
     90				crypto_tfm_ctx_alignment());
     91
     92	ahash_request_set_tfm(req, ahash);
     93
     94	return req;
     95}
     96
     97static inline struct scatterlist *ah_req_sg(struct crypto_ahash *ahash,
     98					     struct ahash_request *req)
     99{
    100	return (void *)ALIGN((unsigned long)(req + 1) +
    101			     crypto_ahash_reqsize(ahash),
    102			     __alignof__(struct scatterlist));
    103}
    104
    105static bool zero_out_mutable_opts(struct ipv6_opt_hdr *opthdr)
    106{
    107	u8 *opt = (u8 *)opthdr;
    108	int len = ipv6_optlen(opthdr);
    109	int off = 0;
    110	int optlen = 0;
    111
    112	off += 2;
    113	len -= 2;
    114
    115	while (len > 0) {
    116
    117		switch (opt[off]) {
    118
    119		case IPV6_TLV_PAD1:
    120			optlen = 1;
    121			break;
    122		default:
    123			if (len < 2)
    124				goto bad;
    125			optlen = opt[off+1]+2;
    126			if (len < optlen)
    127				goto bad;
    128			if (opt[off] & 0x20)
    129				memset(&opt[off+2], 0, opt[off+1]);
    130			break;
    131		}
    132
    133		off += optlen;
    134		len -= optlen;
    135	}
    136	if (len == 0)
    137		return true;
    138
    139bad:
    140	return false;
    141}
    142
    143#if IS_ENABLED(CONFIG_IPV6_MIP6)
    144/**
    145 *	ipv6_rearrange_destopt - rearrange IPv6 destination options header
    146 *	@iph: IPv6 header
    147 *	@destopt: destionation options header
    148 */
    149static void ipv6_rearrange_destopt(struct ipv6hdr *iph, struct ipv6_opt_hdr *destopt)
    150{
    151	u8 *opt = (u8 *)destopt;
    152	int len = ipv6_optlen(destopt);
    153	int off = 0;
    154	int optlen = 0;
    155
    156	off += 2;
    157	len -= 2;
    158
    159	while (len > 0) {
    160
    161		switch (opt[off]) {
    162
    163		case IPV6_TLV_PAD1:
    164			optlen = 1;
    165			break;
    166		default:
    167			if (len < 2)
    168				goto bad;
    169			optlen = opt[off+1]+2;
    170			if (len < optlen)
    171				goto bad;
    172
    173			/* Rearrange the source address in @iph and the
    174			 * addresses in home address option for final source.
    175			 * See 11.3.2 of RFC 3775 for details.
    176			 */
    177			if (opt[off] == IPV6_TLV_HAO) {
    178				struct ipv6_destopt_hao *hao;
    179
    180				hao = (struct ipv6_destopt_hao *)&opt[off];
    181				if (hao->length != sizeof(hao->addr)) {
    182					net_warn_ratelimited("destopt hao: invalid header length: %u\n",
    183							     hao->length);
    184					goto bad;
    185				}
    186				swap(hao->addr, iph->saddr);
    187			}
    188			break;
    189		}
    190
    191		off += optlen;
    192		len -= optlen;
    193	}
    194	/* Note: ok if len == 0 */
    195bad:
    196	return;
    197}
    198#else
    199static void ipv6_rearrange_destopt(struct ipv6hdr *iph, struct ipv6_opt_hdr *destopt) {}
    200#endif
    201
    202/**
    203 *	ipv6_rearrange_rthdr - rearrange IPv6 routing header
    204 *	@iph: IPv6 header
    205 *	@rthdr: routing header
    206 *
    207 *	Rearrange the destination address in @iph and the addresses in @rthdr
    208 *	so that they appear in the order they will at the final destination.
    209 *	See Appendix A2 of RFC 2402 for details.
    210 */
    211static void ipv6_rearrange_rthdr(struct ipv6hdr *iph, struct ipv6_rt_hdr *rthdr)
    212{
    213	int segments, segments_left;
    214	struct in6_addr *addrs;
    215	struct in6_addr final_addr;
    216
    217	segments_left = rthdr->segments_left;
    218	if (segments_left == 0)
    219		return;
    220	rthdr->segments_left = 0;
    221
    222	/* The value of rthdr->hdrlen has been verified either by the system
    223	 * call if it is locally generated, or by ipv6_rthdr_rcv() for incoming
    224	 * packets.  So we can assume that it is even and that segments is
    225	 * greater than or equal to segments_left.
    226	 *
    227	 * For the same reason we can assume that this option is of type 0.
    228	 */
    229	segments = rthdr->hdrlen >> 1;
    230
    231	addrs = ((struct rt0_hdr *)rthdr)->addr;
    232	final_addr = addrs[segments - 1];
    233
    234	addrs += segments - segments_left;
    235	memmove(addrs + 1, addrs, (segments_left - 1) * sizeof(*addrs));
    236
    237	addrs[0] = iph->daddr;
    238	iph->daddr = final_addr;
    239}
    240
    241static int ipv6_clear_mutable_options(struct ipv6hdr *iph, int len, int dir)
    242{
    243	union {
    244		struct ipv6hdr *iph;
    245		struct ipv6_opt_hdr *opth;
    246		struct ipv6_rt_hdr *rth;
    247		char *raw;
    248	} exthdr = { .iph = iph };
    249	char *end = exthdr.raw + len;
    250	int nexthdr = iph->nexthdr;
    251
    252	exthdr.iph++;
    253
    254	while (exthdr.raw < end) {
    255		switch (nexthdr) {
    256		case NEXTHDR_DEST:
    257			if (dir == XFRM_POLICY_OUT)
    258				ipv6_rearrange_destopt(iph, exthdr.opth);
    259			fallthrough;
    260		case NEXTHDR_HOP:
    261			if (!zero_out_mutable_opts(exthdr.opth)) {
    262				net_dbg_ratelimited("overrun %sopts\n",
    263						    nexthdr == NEXTHDR_HOP ?
    264						    "hop" : "dest");
    265				return -EINVAL;
    266			}
    267			break;
    268
    269		case NEXTHDR_ROUTING:
    270			ipv6_rearrange_rthdr(iph, exthdr.rth);
    271			break;
    272
    273		default:
    274			return 0;
    275		}
    276
    277		nexthdr = exthdr.opth->nexthdr;
    278		exthdr.raw += ipv6_optlen(exthdr.opth);
    279	}
    280
    281	return 0;
    282}
    283
    284static void ah6_output_done(struct crypto_async_request *base, int err)
    285{
    286	int extlen;
    287	u8 *iph_base;
    288	u8 *icv;
    289	struct sk_buff *skb = base->data;
    290	struct xfrm_state *x = skb_dst(skb)->xfrm;
    291	struct ah_data *ahp = x->data;
    292	struct ipv6hdr *top_iph = ipv6_hdr(skb);
    293	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
    294	struct tmp_ext *iph_ext;
    295
    296	extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
    297	if (extlen)
    298		extlen += sizeof(*iph_ext);
    299
    300	iph_base = AH_SKB_CB(skb)->tmp;
    301	iph_ext = ah_tmp_ext(iph_base);
    302	icv = ah_tmp_icv(ahp->ahash, iph_ext, extlen);
    303
    304	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
    305	memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
    306
    307	if (extlen) {
    308#if IS_ENABLED(CONFIG_IPV6_MIP6)
    309		memcpy(&top_iph->saddr, iph_ext, extlen);
    310#else
    311		memcpy(&top_iph->daddr, iph_ext, extlen);
    312#endif
    313	}
    314
    315	kfree(AH_SKB_CB(skb)->tmp);
    316	xfrm_output_resume(skb->sk, skb, err);
    317}
    318
    319static int ah6_output(struct xfrm_state *x, struct sk_buff *skb)
    320{
    321	int err;
    322	int nfrags;
    323	int extlen;
    324	u8 *iph_base;
    325	u8 *icv;
    326	u8 nexthdr;
    327	struct sk_buff *trailer;
    328	struct crypto_ahash *ahash;
    329	struct ahash_request *req;
    330	struct scatterlist *sg;
    331	struct ipv6hdr *top_iph;
    332	struct ip_auth_hdr *ah;
    333	struct ah_data *ahp;
    334	struct tmp_ext *iph_ext;
    335	int seqhi_len = 0;
    336	__be32 *seqhi;
    337	int sglists = 0;
    338	struct scatterlist *seqhisg;
    339
    340	ahp = x->data;
    341	ahash = ahp->ahash;
    342
    343	err = skb_cow_data(skb, 0, &trailer);
    344	if (err < 0)
    345		goto out;
    346	nfrags = err;
    347
    348	skb_push(skb, -skb_network_offset(skb));
    349	extlen = skb_network_header_len(skb) - sizeof(struct ipv6hdr);
    350	if (extlen)
    351		extlen += sizeof(*iph_ext);
    352
    353	if (x->props.flags & XFRM_STATE_ESN) {
    354		sglists = 1;
    355		seqhi_len = sizeof(*seqhi);
    356	}
    357	err = -ENOMEM;
    358	iph_base = ah_alloc_tmp(ahash, nfrags + sglists, IPV6HDR_BASELEN +
    359				extlen + seqhi_len);
    360	if (!iph_base)
    361		goto out;
    362
    363	iph_ext = ah_tmp_ext(iph_base);
    364	seqhi = (__be32 *)((char *)iph_ext + extlen);
    365	icv = ah_tmp_icv(ahash, seqhi, seqhi_len);
    366	req = ah_tmp_req(ahash, icv);
    367	sg = ah_req_sg(ahash, req);
    368	seqhisg = sg + nfrags;
    369
    370	ah = ip_auth_hdr(skb);
    371	memset(ah->auth_data, 0, ahp->icv_trunc_len);
    372
    373	top_iph = ipv6_hdr(skb);
    374	top_iph->payload_len = htons(skb->len - sizeof(*top_iph));
    375
    376	nexthdr = *skb_mac_header(skb);
    377	*skb_mac_header(skb) = IPPROTO_AH;
    378
    379	/* When there are no extension headers, we only need to save the first
    380	 * 8 bytes of the base IP header.
    381	 */
    382	memcpy(iph_base, top_iph, IPV6HDR_BASELEN);
    383
    384	if (extlen) {
    385#if IS_ENABLED(CONFIG_IPV6_MIP6)
    386		memcpy(iph_ext, &top_iph->saddr, extlen);
    387#else
    388		memcpy(iph_ext, &top_iph->daddr, extlen);
    389#endif
    390		err = ipv6_clear_mutable_options(top_iph,
    391						 extlen - sizeof(*iph_ext) +
    392						 sizeof(*top_iph),
    393						 XFRM_POLICY_OUT);
    394		if (err)
    395			goto out_free;
    396	}
    397
    398	ah->nexthdr = nexthdr;
    399
    400	top_iph->priority    = 0;
    401	top_iph->flow_lbl[0] = 0;
    402	top_iph->flow_lbl[1] = 0;
    403	top_iph->flow_lbl[2] = 0;
    404	top_iph->hop_limit   = 0;
    405
    406	ah->hdrlen  = (XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len) >> 2) - 2;
    407
    408	ah->reserved = 0;
    409	ah->spi = x->id.spi;
    410	ah->seq_no = htonl(XFRM_SKB_CB(skb)->seq.output.low);
    411
    412	sg_init_table(sg, nfrags + sglists);
    413	err = skb_to_sgvec_nomark(skb, sg, 0, skb->len);
    414	if (unlikely(err < 0))
    415		goto out_free;
    416
    417	if (x->props.flags & XFRM_STATE_ESN) {
    418		/* Attach seqhi sg right after packet payload */
    419		*seqhi = htonl(XFRM_SKB_CB(skb)->seq.output.hi);
    420		sg_set_buf(seqhisg, seqhi, seqhi_len);
    421	}
    422	ahash_request_set_crypt(req, sg, icv, skb->len + seqhi_len);
    423	ahash_request_set_callback(req, 0, ah6_output_done, skb);
    424
    425	AH_SKB_CB(skb)->tmp = iph_base;
    426
    427	err = crypto_ahash_digest(req);
    428	if (err) {
    429		if (err == -EINPROGRESS)
    430			goto out;
    431
    432		if (err == -ENOSPC)
    433			err = NET_XMIT_DROP;
    434		goto out_free;
    435	}
    436
    437	memcpy(ah->auth_data, icv, ahp->icv_trunc_len);
    438	memcpy(top_iph, iph_base, IPV6HDR_BASELEN);
    439
    440	if (extlen) {
    441#if IS_ENABLED(CONFIG_IPV6_MIP6)
    442		memcpy(&top_iph->saddr, iph_ext, extlen);
    443#else
    444		memcpy(&top_iph->daddr, iph_ext, extlen);
    445#endif
    446	}
    447
    448out_free:
    449	kfree(iph_base);
    450out:
    451	return err;
    452}
    453
    454static void ah6_input_done(struct crypto_async_request *base, int err)
    455{
    456	u8 *auth_data;
    457	u8 *icv;
    458	u8 *work_iph;
    459	struct sk_buff *skb = base->data;
    460	struct xfrm_state *x = xfrm_input_state(skb);
    461	struct ah_data *ahp = x->data;
    462	struct ip_auth_hdr *ah = ip_auth_hdr(skb);
    463	int hdr_len = skb_network_header_len(skb);
    464	int ah_hlen = ipv6_authlen(ah);
    465
    466	if (err)
    467		goto out;
    468
    469	work_iph = AH_SKB_CB(skb)->tmp;
    470	auth_data = ah_tmp_auth(work_iph, hdr_len);
    471	icv = ah_tmp_icv(ahp->ahash, auth_data, ahp->icv_trunc_len);
    472
    473	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
    474	if (err)
    475		goto out;
    476
    477	err = ah->nexthdr;
    478
    479	skb->network_header += ah_hlen;
    480	memcpy(skb_network_header(skb), work_iph, hdr_len);
    481	__skb_pull(skb, ah_hlen + hdr_len);
    482	if (x->props.mode == XFRM_MODE_TUNNEL)
    483		skb_reset_transport_header(skb);
    484	else
    485		skb_set_transport_header(skb, -hdr_len);
    486out:
    487	kfree(AH_SKB_CB(skb)->tmp);
    488	xfrm_input_resume(skb, err);
    489}
    490
    491
    492
    493static int ah6_input(struct xfrm_state *x, struct sk_buff *skb)
    494{
    495	/*
    496	 * Before process AH
    497	 * [IPv6][Ext1][Ext2][AH][Dest][Payload]
    498	 * |<-------------->| hdr_len
    499	 *
    500	 * To erase AH:
    501	 * Keeping copy of cleared headers. After AH processing,
    502	 * Moving the pointer of skb->network_header by using skb_pull as long
    503	 * as AH header length. Then copy back the copy as long as hdr_len
    504	 * If destination header following AH exists, copy it into after [Ext2].
    505	 *
    506	 * |<>|[IPv6][Ext1][Ext2][Dest][Payload]
    507	 * There is offset of AH before IPv6 header after the process.
    508	 */
    509
    510	u8 *auth_data;
    511	u8 *icv;
    512	u8 *work_iph;
    513	struct sk_buff *trailer;
    514	struct crypto_ahash *ahash;
    515	struct ahash_request *req;
    516	struct scatterlist *sg;
    517	struct ip_auth_hdr *ah;
    518	struct ipv6hdr *ip6h;
    519	struct ah_data *ahp;
    520	u16 hdr_len;
    521	u16 ah_hlen;
    522	int nexthdr;
    523	int nfrags;
    524	int err = -ENOMEM;
    525	int seqhi_len = 0;
    526	__be32 *seqhi;
    527	int sglists = 0;
    528	struct scatterlist *seqhisg;
    529
    530	if (!pskb_may_pull(skb, sizeof(struct ip_auth_hdr)))
    531		goto out;
    532
    533	/* We are going to _remove_ AH header to keep sockets happy,
    534	 * so... Later this can change. */
    535	if (skb_unclone(skb, GFP_ATOMIC))
    536		goto out;
    537
    538	skb->ip_summed = CHECKSUM_NONE;
    539
    540	hdr_len = skb_network_header_len(skb);
    541	ah = (struct ip_auth_hdr *)skb->data;
    542	ahp = x->data;
    543	ahash = ahp->ahash;
    544
    545	nexthdr = ah->nexthdr;
    546	ah_hlen = ipv6_authlen(ah);
    547
    548	if (ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_full_len) &&
    549	    ah_hlen != XFRM_ALIGN8(sizeof(*ah) + ahp->icv_trunc_len))
    550		goto out;
    551
    552	if (!pskb_may_pull(skb, ah_hlen))
    553		goto out;
    554
    555	err = skb_cow_data(skb, 0, &trailer);
    556	if (err < 0)
    557		goto out;
    558	nfrags = err;
    559
    560	ah = (struct ip_auth_hdr *)skb->data;
    561	ip6h = ipv6_hdr(skb);
    562
    563	skb_push(skb, hdr_len);
    564
    565	if (x->props.flags & XFRM_STATE_ESN) {
    566		sglists = 1;
    567		seqhi_len = sizeof(*seqhi);
    568	}
    569
    570	work_iph = ah_alloc_tmp(ahash, nfrags + sglists, hdr_len +
    571				ahp->icv_trunc_len + seqhi_len);
    572	if (!work_iph) {
    573		err = -ENOMEM;
    574		goto out;
    575	}
    576
    577	auth_data = ah_tmp_auth((u8 *)work_iph, hdr_len);
    578	seqhi = (__be32 *)(auth_data + ahp->icv_trunc_len);
    579	icv = ah_tmp_icv(ahash, seqhi, seqhi_len);
    580	req = ah_tmp_req(ahash, icv);
    581	sg = ah_req_sg(ahash, req);
    582	seqhisg = sg + nfrags;
    583
    584	memcpy(work_iph, ip6h, hdr_len);
    585	memcpy(auth_data, ah->auth_data, ahp->icv_trunc_len);
    586	memset(ah->auth_data, 0, ahp->icv_trunc_len);
    587
    588	err = ipv6_clear_mutable_options(ip6h, hdr_len, XFRM_POLICY_IN);
    589	if (err)
    590		goto out_free;
    591
    592	ip6h->priority    = 0;
    593	ip6h->flow_lbl[0] = 0;
    594	ip6h->flow_lbl[1] = 0;
    595	ip6h->flow_lbl[2] = 0;
    596	ip6h->hop_limit   = 0;
    597
    598	sg_init_table(sg, nfrags + sglists);
    599	err = skb_to_sgvec_nomark(skb, sg, 0, skb->len);
    600	if (unlikely(err < 0))
    601		goto out_free;
    602
    603	if (x->props.flags & XFRM_STATE_ESN) {
    604		/* Attach seqhi sg right after packet payload */
    605		*seqhi = XFRM_SKB_CB(skb)->seq.input.hi;
    606		sg_set_buf(seqhisg, seqhi, seqhi_len);
    607	}
    608
    609	ahash_request_set_crypt(req, sg, icv, skb->len + seqhi_len);
    610	ahash_request_set_callback(req, 0, ah6_input_done, skb);
    611
    612	AH_SKB_CB(skb)->tmp = work_iph;
    613
    614	err = crypto_ahash_digest(req);
    615	if (err) {
    616		if (err == -EINPROGRESS)
    617			goto out;
    618
    619		goto out_free;
    620	}
    621
    622	err = crypto_memneq(icv, auth_data, ahp->icv_trunc_len) ? -EBADMSG : 0;
    623	if (err)
    624		goto out_free;
    625
    626	skb->network_header += ah_hlen;
    627	memcpy(skb_network_header(skb), work_iph, hdr_len);
    628	__skb_pull(skb, ah_hlen + hdr_len);
    629
    630	if (x->props.mode == XFRM_MODE_TUNNEL)
    631		skb_reset_transport_header(skb);
    632	else
    633		skb_set_transport_header(skb, -hdr_len);
    634
    635	err = nexthdr;
    636
    637out_free:
    638	kfree(work_iph);
    639out:
    640	return err;
    641}
    642
    643static int ah6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
    644		   u8 type, u8 code, int offset, __be32 info)
    645{
    646	struct net *net = dev_net(skb->dev);
    647	struct ipv6hdr *iph = (struct ipv6hdr *)skb->data;
    648	struct ip_auth_hdr *ah = (struct ip_auth_hdr *)(skb->data+offset);
    649	struct xfrm_state *x;
    650
    651	if (type != ICMPV6_PKT_TOOBIG &&
    652	    type != NDISC_REDIRECT)
    653		return 0;
    654
    655	x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET6);
    656	if (!x)
    657		return 0;
    658
    659	if (type == NDISC_REDIRECT)
    660		ip6_redirect(skb, net, skb->dev->ifindex, 0,
    661			     sock_net_uid(net, NULL));
    662	else
    663		ip6_update_pmtu(skb, net, info, 0, 0, sock_net_uid(net, NULL));
    664	xfrm_state_put(x);
    665
    666	return 0;
    667}
    668
    669static int ah6_init_state(struct xfrm_state *x)
    670{
    671	struct ah_data *ahp = NULL;
    672	struct xfrm_algo_desc *aalg_desc;
    673	struct crypto_ahash *ahash;
    674
    675	if (!x->aalg)
    676		goto error;
    677
    678	if (x->encap)
    679		goto error;
    680
    681	ahp = kzalloc(sizeof(*ahp), GFP_KERNEL);
    682	if (!ahp)
    683		return -ENOMEM;
    684
    685	ahash = crypto_alloc_ahash(x->aalg->alg_name, 0, 0);
    686	if (IS_ERR(ahash))
    687		goto error;
    688
    689	ahp->ahash = ahash;
    690	if (crypto_ahash_setkey(ahash, x->aalg->alg_key,
    691			       (x->aalg->alg_key_len + 7) / 8))
    692		goto error;
    693
    694	/*
    695	 * Lookup the algorithm description maintained by xfrm_algo,
    696	 * verify crypto transform properties, and store information
    697	 * we need for AH processing.  This lookup cannot fail here
    698	 * after a successful crypto_alloc_hash().
    699	 */
    700	aalg_desc = xfrm_aalg_get_byname(x->aalg->alg_name, 0);
    701	BUG_ON(!aalg_desc);
    702
    703	if (aalg_desc->uinfo.auth.icv_fullbits/8 !=
    704	    crypto_ahash_digestsize(ahash)) {
    705		pr_info("AH: %s digestsize %u != %u\n",
    706			x->aalg->alg_name, crypto_ahash_digestsize(ahash),
    707			aalg_desc->uinfo.auth.icv_fullbits/8);
    708		goto error;
    709	}
    710
    711	ahp->icv_full_len = aalg_desc->uinfo.auth.icv_fullbits/8;
    712	ahp->icv_trunc_len = x->aalg->alg_trunc_len/8;
    713
    714	x->props.header_len = XFRM_ALIGN8(sizeof(struct ip_auth_hdr) +
    715					  ahp->icv_trunc_len);
    716	switch (x->props.mode) {
    717	case XFRM_MODE_BEET:
    718	case XFRM_MODE_TRANSPORT:
    719		break;
    720	case XFRM_MODE_TUNNEL:
    721		x->props.header_len += sizeof(struct ipv6hdr);
    722		break;
    723	default:
    724		goto error;
    725	}
    726	x->data = ahp;
    727
    728	return 0;
    729
    730error:
    731	if (ahp) {
    732		crypto_free_ahash(ahp->ahash);
    733		kfree(ahp);
    734	}
    735	return -EINVAL;
    736}
    737
    738static void ah6_destroy(struct xfrm_state *x)
    739{
    740	struct ah_data *ahp = x->data;
    741
    742	if (!ahp)
    743		return;
    744
    745	crypto_free_ahash(ahp->ahash);
    746	kfree(ahp);
    747}
    748
    749static int ah6_rcv_cb(struct sk_buff *skb, int err)
    750{
    751	return 0;
    752}
    753
    754static const struct xfrm_type ah6_type = {
    755	.owner		= THIS_MODULE,
    756	.proto		= IPPROTO_AH,
    757	.flags		= XFRM_TYPE_REPLAY_PROT,
    758	.init_state	= ah6_init_state,
    759	.destructor	= ah6_destroy,
    760	.input		= ah6_input,
    761	.output		= ah6_output,
    762};
    763
    764static struct xfrm6_protocol ah6_protocol = {
    765	.handler	=	xfrm6_rcv,
    766	.input_handler	=	xfrm_input,
    767	.cb_handler	=	ah6_rcv_cb,
    768	.err_handler	=	ah6_err,
    769	.priority	=	0,
    770};
    771
    772static int __init ah6_init(void)
    773{
    774	if (xfrm_register_type(&ah6_type, AF_INET6) < 0) {
    775		pr_info("%s: can't add xfrm type\n", __func__);
    776		return -EAGAIN;
    777	}
    778
    779	if (xfrm6_protocol_register(&ah6_protocol, IPPROTO_AH) < 0) {
    780		pr_info("%s: can't add protocol\n", __func__);
    781		xfrm_unregister_type(&ah6_type, AF_INET6);
    782		return -EAGAIN;
    783	}
    784
    785	return 0;
    786}
    787
    788static void __exit ah6_fini(void)
    789{
    790	if (xfrm6_protocol_deregister(&ah6_protocol, IPPROTO_AH) < 0)
    791		pr_info("%s: can't remove protocol\n", __func__);
    792
    793	xfrm_unregister_type(&ah6_type, AF_INET6);
    794}
    795
    796module_init(ah6_init);
    797module_exit(ah6_fini);
    798
    799MODULE_LICENSE("GPL");
    800MODULE_ALIAS_XFRM_TYPE(AF_INET6, XFRM_PROTO_AH);