コード例 #1
0
ファイル: ipsec_sa.c プロジェクト: yottanami/libreswan
struct ipsec_sa *__ipsec_sa_get(struct ipsec_sa *ips, const char *func,
				int line, int type)
{
	if (ips == NULL)
		return NULL;

	if (debug_xform) {
		char sa[SATOT_BUF];
		size_t sa_len;
		sa_len = KLIPS_SATOT(debug_xform, &ips->ips_said, 0, sa,
				     sizeof(sa));

		KLIPS_PRINT(debug_xform,
			    "ipsec_sa_get: "
			    "ipsec_sa %p SA:%s, ref:%d reference count (%d++) incremented by %s:%d.\n",
			    ips,
			    sa_len ? sa : " (error)",
			    ips->ips_ref,
			    atomic_read(&ips->ips_refcount),
			    func, line);
	}

	atomic_inc(&ips->ips_refcount);

#ifdef IPSEC_SA_RECOUNT_DEBUG
	if (type >= 0 && type < sizeof(ips->ips_track)) {
		unsigned long flags;
		local_irq_save(flags);
		if (ips->ips_track[type] == 255)
			printk("ipsec_sa_get: OVERFLOW for %d @ %s %d\n", type,
			       func, line);
		else
			ips->ips_track[type]++;
		local_irq_restore(flags);
	} else {
		printk("BAD BAD BAD @ %s %d\n", func, line);
	}
#endif

#if 0
	/*
	 * DAVIDM: if we include this code it means the SA is freed immediately
	 * on creation and then reused ! Not sure why it is here.
	 */

	if (atomic_dec_and_test(&ips->ips_refcount)) {
		KLIPS_PRINT(debug_xform,
			    "ipsec_sa_get: freeing %p\n",
			    ips);
		/* it was zero */
		ipsec_sa_wipe(ips);
	}
#endif

	return ips;
}
コード例 #2
0
ファイル: ipsec_sa.c プロジェクト: yottanami/libreswan
int ipsec_sa_print(struct ipsec_sa *ips)
{
	char sa[SATOT_BUF];
	size_t sa_len;

	printk(KERN_INFO "klips_debug:   SA:");
	if (ips == NULL) {
		printk("NULL\n");
		return -ENOENT;
	}
	printk(" ref=%d", ips->ips_ref);
	printk(" refcount=%d", atomic_read(&ips->ips_refcount));
	if (ips->ips_hnext != NULL)
		printk(" hnext=0p%p", ips->ips_hnext);
	if (ips->ips_next != NULL)
		printk(" next=0p%p", ips->ips_next);
	if (ips->ips_prev != NULL)
		printk(" prev=0p%p", ips->ips_prev);
	sa_len = KLIPS_SATOT(1, &ips->ips_said, 0, sa, sizeof(sa));
	printk(" said=%s", sa_len ? sa : " (error)");
	if (ips->ips_seq)
		printk(" seq=%u", ips->ips_seq);
	if (ips->ips_pid)
		printk(" pid=%u", ips->ips_pid);
	if (ips->ips_authalg)
		printk(" authalg=%u", ips->ips_authalg);
	if (ips->ips_encalg)
		printk(" encalg=%u", ips->ips_encalg);
	printk(" XFORM=%s%s%s", IPS_XFORM_NAME(ips));
	if (ips->ips_replaywin)
		printk(" ooowin=%u", ips->ips_replaywin);
	if (ips->ips_flags)
		printk(" flags=%u", ips->ips_flags);
	if (ips->ips_addr_s) {
		char buf[SUBNETTOA_BUF];
		sin_addrtot(ips->ips_addr_s, 0, buf, sizeof(buf));
		printk(" src=%s", buf);
	}
	if (ips->ips_addr_d) {
		char buf[SUBNETTOA_BUF];
		sin_addrtot(ips->ips_addr_s, 0, buf, sizeof(buf));
		printk(" dst=%s", buf);
	}
	if (ips->ips_addr_p) {
		char buf[SUBNETTOA_BUF];
		sin_addrtot(ips->ips_addr_p, 0, buf, sizeof(buf));
		printk(" proxy=%s", buf);
	}
	if (ips->ips_key_bits_a)
		printk(" key_bits_a=%u", ips->ips_key_bits_a);
	if (ips->ips_key_bits_e)
		printk(" key_bits_e=%u", ips->ips_key_bits_e);

	printk("\n");
	return 0;
}
コード例 #3
0
ファイル: ipsec_sa.c プロジェクト: mcr/bluerose
/*
 * remove it from the hash chain, decrementing hash count
 */
void ipsec_sa_rm(struct ipsec_sa *ips)
{
	unsigned int hashval;
        char sa[SATOT_BUF];
	size_t sa_len;


	if(ips == NULL) {
                return;
        }


	hashval = IPS_HASH(&ips->ips_said);

	sa_len = KLIPS_SATOT(debug_xform, &ips->ips_said, 0, sa, sizeof(sa));
	KLIPS_PRINT(debug_xform,
		    "klips_debug:ipsec_sa_del: "
		    "unhashing SA:%s (ref=%u), hashval=%d.\n",
		    sa_len ? sa : " (error)",
		    ips->ips_ref,
		    hashval);

	if(ipsec_sadb_hash[hashval] == NULL) {
		return;
	}
	
	if (ips == ipsec_sadb_hash[hashval]) {
		ipsec_sadb_hash[hashval] = ipsec_sadb_hash[hashval]->ips_hnext;
		ips->ips_hnext = NULL;
		ipsec_sa_put(ips);
		KLIPS_PRINT(debug_xform,
			    "klips_debug:ipsec_sa_del: "
			    "successfully unhashed first ipsec_sa in chain.\n");
		return;
	} else {
		struct ipsec_sa *ipstp;

		for (ipstp = ipsec_sadb_hash[hashval];
		     ipstp;
		     ipstp = ipstp->ips_hnext) {
			if (ipstp->ips_hnext == ips) {
				ipstp->ips_hnext = ips->ips_hnext;
				ips->ips_hnext = NULL;
				ipsec_sa_put(ips);
				KLIPS_PRINT(debug_xform,
					    "klips_debug:ipsec_sa_del: "
					    "successfully unhashed link in ipsec_sa chain.\n");
				return;
			}
		}
	}
}
コード例 #4
0
ファイル: ipsec_sa.c プロジェクト: hydromet/libreswan
void __ipsec_sa_put(struct ipsec_sa *ips, const char *func, int line, int type)
{
	if (ips == NULL) {
		KLIPS_PRINT(debug_xform,
			    "ipsec_sa_put: "
			    "null pointer passed in!\n");
		return;
	}

	if (debug_xform) {
		char sa[SATOT_BUF];
		size_t sa_len;
		sa_len = KLIPS_SATOT(debug_xform, &ips->ips_said, 0, sa,
				     sizeof(sa));

		KLIPS_PRINT(debug_xform,
			    "ipsec_sa_put: "
			    "ipsec_sa %p SA:%s, ref:%d reference count (%d--) decremented by %s:%d.\n",
			    ips,
			    sa_len ? sa : " (error)",
			    ips->ips_ref,
			    atomic_read(&ips->ips_refcount),
			    func, line);
	}

#ifdef IPSEC_SA_RECOUNT_DEBUG
	if (type >= 0 && type < sizeof(ips->ips_track)) {
		unsigned long flags;
		local_irq_save(flags);
		if (ips->ips_track[type] == 0)
			printk("ipsec_sa_put: UNDERFLOW for %d @ %s %d\n",
			       type, func, line);
		else
			ips->ips_track[type]--;
		local_irq_restore(flags);
	} else {
		printk("BAD BAD BAD @ %s %d\n", func, line);
	}
#endif

	if (atomic_dec_and_test(&ips->ips_refcount)) {
		KLIPS_PRINT(debug_xform,
			    "ipsec_sa_put: freeing %p\n",
			    ips);
		/* it was zero */
		ipsec_sa_wipe(ips);
	}

	return;
}
コード例 #5
0
ファイル: ipsec_sa.c プロジェクト: st3fan/libreswan
struct ipsec_sa *
ipsec_sa_getbyid(ip_said *said, int type)
{
	int hashval;
	struct ipsec_sa *ips;
        char sa[SATOT_BUF];
	size_t sa_len;

	if(said == NULL) {
		KLIPS_PRINT(debug_xform,
			    "ipsec_sa_getbyid: "
			    "null pointer passed in!\n");
		return NULL;
	}

	hashval = IPS_HASH(said);
	
	sa_len = KLIPS_SATOT(debug_xform, said, 0, sa, sizeof(sa));
	KLIPS_PRINT(debug_xform,
		    "ipsec_sa_getbyid: "
		    "linked entry in ipsec_sa table for hash=%d of SA:%s requested.\n",
		    hashval,
		    sa_len ? sa : " (error)");

	if((ips = ipsec_sadb_hash[hashval]) == NULL) {
		KLIPS_PRINT(debug_xform,
			    "ipsec_sa_getbyid: "
			    "no entries in ipsec_sa table for hash=%d of SA:%s.\n",
			    hashval,
			    sa_len ? sa : " (error)");
		return NULL;
	}

	for (; ips; ips = ips->ips_hnext) {
		if ((ips->ips_said.spi == said->spi) &&
		    (ip_address_cmp(&ips->ips_said.dst, &said->dst) == 0) &&
		    (ips->ips_said.proto == said->proto)) {
			ipsec_sa_get(ips, type);
			return ips;
		}
	}
	
	KLIPS_PRINT(debug_xform,
		    "ipsec_sa_getbyid: "
		    "no entry in linked list for hash=%d of SA:%s.\n",
		    hashval,
		    sa_len ? sa : " (error)");
	return NULL;
}
コード例 #6
0
ファイル: ipsec_ipcomp.c プロジェクト: libreswan/libreswan
enum ipsec_rcv_value ipsec_rcv_ipcomp_decomp(struct ipsec_rcv_state *irs)
{
	unsigned int flags = 0;
	struct ipsec_sa *ipsp = irs->ipsp;
	struct sk_buff *skb;

	skb = irs->skb;

	ipsec_xmit_dmp("ipcomp", skb_transport_header(skb), skb->len);

	if (ipsp == NULL)
		return IPSEC_RCV_SAIDNOTFOUND;

	if (sysctl_ipsec_inbound_policy_check &&
	    ((((ntohl(ipsp->ips_said.spi) & 0x0000ffff) !=
	       (ntohl(irs->said.spi) & 0x0000ffff)) &&
	      (ipsp->ips_encalg != ntohl(irs->said.spi))  /* this is a workaround for peer non-compliance with rfc2393 */
	      ))) {
		char sa2[SATOT_BUF];
		size_t sa_len2 = 0;

		sa_len2 = KLIPS_SATOT(debug_rcv, &ipsp->ips_said, 0, sa2,
				      sizeof(sa2));

		KLIPS_PRINT(debug_rcv,
			    "klips_debug:ipsec_rcv_ipcomp_decomp: "
			    "Incoming packet with SA(IPCA):%s does not match policy SA(IPCA):%s cpi=%04x cpi->spi=%08x spi=%08x, spi->cpi=%04x for SA grouping, dropped.\n",
			    irs->sa_len ? irs->sa : " (error)",
			    sa_len2 ? sa2 : " (error)",
			    ntohs(irs->protostuff.ipcompstuff.compp->ipcomp_cpi),
			    (__u32)ntohl(irs->said.spi),
			    (__u32)ntohl((ipsp->ips_said.spi)),
			    (__u16)(ntohl(ipsp->ips_said.spi) & 0x0000ffff));
		if (irs->stats)
			irs->stats->rx_dropped++;
		return IPSEC_RCV_SAIDNOTFOUND;
	}

	if (lsw_ip_hdr_version(irs) == 6)
		ipsp->ips_comp_ratio_cbytes +=
			ntohs(lsw_ip6_hdr(irs)->payload_len) +
			sizeof(struct ipv6hdr);
	else
		ipsp->ips_comp_ratio_cbytes +=
			ntohs(lsw_ip4_hdr(irs)->tot_len);
	irs->next_header = irs->protostuff.ipcompstuff.compp->ipcomp_nh;

#ifdef CONFIG_KLIPS_OCF
	if (irs->ipsp->ocf_in_use)
		return ipsec_ocf_rcv(irs);

#endif

	skb = skb_decompress(skb, ipsp, &flags);
	if (!skb || flags) {
		KLIPS_PRINT(debug_rcv,
			    "klips_debug:ipsec_rcv_ipcomp_decomp: "
			    "skb_decompress() returned error flags=%x, dropped.\n",
			    flags);
		if (irs->stats) {
			if (flags)
				irs->stats->rx_errors++;
			else
				irs->stats->rx_dropped++;
		}
		return IPSEC_RCV_IPCOMPFAILED;
	}

	/* make sure we update the pointer */
	irs->skb = skb;

	irs->iph = (void *) ip_hdr(skb);

	if (lsw_ip_hdr_version(irs) == 6)
		ipsp->ips_comp_ratio_dbytes +=
			ntohs(lsw_ip6_hdr(irs)->payload_len) +
			sizeof(struct ipv6hdr);
	else
		ipsp->ips_comp_ratio_dbytes +=
			ntohs(lsw_ip4_hdr(irs)->tot_len);

	KLIPS_PRINT(debug_rcv,
		    "klips_debug:ipsec_rcv_ipcomp_decomp: "
		    "packet decompressed SA(IPCA):%s cpi->spi=%08x spi=%08x, spi->cpi=%04x, nh=%d.\n",
		    irs->sa_len ? irs->sa : " (error)",
		    (__u32)ntohl(irs->said.spi),
		    ipsp != NULL ? (__u32)ntohl((ipsp->ips_said.spi)) : 0,
		    ipsp != NULL ?
		      (__u16)(ntohl(ipsp->ips_said.spi) & 0x0000ffff) : 0,
		    irs->next_header);
	KLIPS_IP_PRINT(debug_rcv & DB_RX_PKTRX, irs->iph);

	return IPSEC_RCV_OK;
}
コード例 #7
0
ファイル: ipsec_mast.c プロジェクト: OPSF/uClinux
/*
 * Verify that the skb can go out on this ipsp.
 * Return 0 if OK, error code otherwise.
 */
static int
ipsec_mast_check_outbound_policy(struct ipsec_xmit_state *ixs)
{
	int failed_outbound_check = 0;
	struct ipsec_sa *ipsp = ixs->ipsp;

	if (!ixs || !ixs->ipsp || !ixs->iph)
		return -EFAULT;

	/* Note: "xor" (^) logically replaces "not equal"
	 * (!=) and "bitwise or" (|) logically replaces
	 * "boolean or" (||).  This is done to speed up
	 * execution by doing only bitwise operations and
	 * no branch operations */
	if (osw_ip_hdr_version(ixs) == 4) {
		struct iphdr *ipp = osw_ip4_hdr(ixs);
		if (ip_address_family(&ipsp->ips_said.dst) != AF_INET) {
			failed_outbound_check = 1;
		} else if (((ipp->saddr & ipsp->ips_mask_s.u.v4.sin_addr.s_addr)
				^ ipsp->ips_flow_s.u.v4.sin_addr.s_addr)
				| ((ipp->daddr & ipsp->ips_mask_d.u.v4.sin_addr.s_addr)
				^ ipsp->ips_flow_d.u.v4.sin_addr.s_addr)) {
			failed_outbound_check = 1;
		}
	} else if (osw_ip_hdr_version(ixs) == 6) {
		struct ipv6hdr *ipp6 = osw_ip6_hdr(ixs);
		if (ip_address_family(&ipsp->ips_said.dst) != AF_INET6) {
			failed_outbound_check = 1;
		} else if (((ipp6->saddr.s6_addr32[0] & ipsp->ips_mask_s.u.v6.sin6_addr.s6_addr32[0])
				^ ipsp->ips_flow_s.u.v6.sin6_addr.s6_addr32[0])
				| ((ipp6->daddr.s6_addr32[0] & ipsp->ips_mask_d.u.v6.sin6_addr.s6_addr32[0])
				^ ipsp->ips_flow_d.u.v6.sin6_addr.s6_addr32[0])) {
			failed_outbound_check = 1;
		} else if (((ipp6->saddr.s6_addr32[1] & ipsp->ips_mask_s.u.v6.sin6_addr.s6_addr32[1])
				^ ipsp->ips_flow_s.u.v6.sin6_addr.s6_addr32[1])
				| ((ipp6->daddr.s6_addr32[1] & ipsp->ips_mask_d.u.v6.sin6_addr.s6_addr32[1])
				^ ipsp->ips_flow_d.u.v6.sin6_addr.s6_addr32[1])) {
			failed_outbound_check = 1;
		} else if (((ipp6->saddr.s6_addr32[2] & ipsp->ips_mask_s.u.v6.sin6_addr.s6_addr32[2])
				^ ipsp->ips_flow_s.u.v6.sin6_addr.s6_addr32[2])
				| ((ipp6->daddr.s6_addr32[2] & ipsp->ips_mask_d.u.v6.sin6_addr.s6_addr32[2])
				^ ipsp->ips_flow_d.u.v6.sin6_addr.s6_addr32[2])) {
			failed_outbound_check = 1;
		} else if (((ipp6->saddr.s6_addr32[3] & ipsp->ips_mask_s.u.v6.sin6_addr.s6_addr32[3])
				^ ipsp->ips_flow_s.u.v6.sin6_addr.s6_addr32[3])
				| ((ipp6->daddr.s6_addr32[3] & ipsp->ips_mask_d.u.v6.sin6_addr.s6_addr32[3])
				^ ipsp->ips_flow_d.u.v6.sin6_addr.s6_addr32[3])) {
			failed_outbound_check = 1;
		}
	}
	if (failed_outbound_check) {
		char saddr_txt[ADDRTOA_BUF], daddr_txt[ADDRTOA_BUF];
		char sflow_txt[SUBNETTOA_BUF], dflow_txt[SUBNETTOA_BUF];

		if (ipsp->ips_flow_s.u.v4.sin_family == AF_INET6) {
			subnet6toa(&ipsp->ips_flow_s.u.v6.sin6_addr,
					&ipsp->ips_mask_s.u.v6.sin6_addr,
					0, sflow_txt, sizeof(sflow_txt));
			subnet6toa(&ipsp->ips_flow_d.u.v6.sin6_addr,
					&ipsp->ips_mask_d.u.v6.sin6_addr,
					0, dflow_txt, sizeof(dflow_txt));
			inet_addrtot(AF_INET6, &osw_ip6_hdr(ixs)->saddr, 0, saddr_txt,
					sizeof(saddr_txt));
			inet_addrtot(AF_INET6, &osw_ip6_hdr(ixs)->daddr, 0, daddr_txt,
					sizeof(daddr_txt));
		} else {
			subnettoa(ipsp->ips_flow_s.u.v4.sin_addr,
					ipsp->ips_mask_s.u.v4.sin_addr,
					0, sflow_txt, sizeof(sflow_txt));
			subnettoa(ipsp->ips_flow_d.u.v4.sin_addr,
					ipsp->ips_mask_d.u.v4.sin_addr,
					0, dflow_txt, sizeof(dflow_txt));
			inet_addrtot(AF_INET, &osw_ip4_hdr(ixs)->saddr, 0, saddr_txt,
					sizeof(saddr_txt));
			inet_addrtot(AF_INET, &osw_ip4_hdr(ixs)->daddr, 0, daddr_txt,
					sizeof(daddr_txt));
		}

		if (!ixs->sa_len) ixs->sa_len = KLIPS_SATOT(debug_mast,
				&ixs->outgoing_said, 0,
				ixs->sa_txt, sizeof(ixs->sa_txt));

		KLIPS_PRINT(debug_mast,
			    "klips_debug:ipsec_mast_check_outbound_policy: "
			    "SA:%s, inner tunnel policy [%s -> %s] does not agree with pkt contents [%s -> %s].\n",
			    ixs->sa_len ? ixs->sa_txt : " (error)",
			    sflow_txt, dflow_txt, saddr_txt, daddr_txt);
		if(ixs->stats)
			ixs->stats->rx_dropped++;
		return -EACCES;
	}

#if 0
	{
		char sflow_txt[SUBNETTOA_BUF], dflow_txt[SUBNETTOA_BUF];
		char saddr_txt[ADDRTOA_BUF], daddr_txt[ADDRTOA_BUF];
		struct in_addr ipaddr;

		subnettoa(ixs->ipsp->ips_flow_s.u.v4.sin_addr,
			  ixs->ipsp->ips_mask_s.u.v4.sin_addr,
			  0, sflow_txt, sizeof(sflow_txt));
		subnettoa(ixs->ipsp->ips_flow_d.u.v4.sin_addr,
			  ixs->ipsp->ips_mask_d.u.v4.sin_addr,
			  0, dflow_txt, sizeof(dflow_txt));

		ipaddr.s_addr = ixs->iph->saddr;
		addrtoa(ipaddr, 0, saddr_txt, sizeof(saddr_txt));
		ipaddr.s_addr = ixs->iph->daddr;
		addrtoa(ipaddr, 0, daddr_txt, sizeof(daddr_txt));

		if (!ixs->sa_len) ixs->sa_len = KLIPS_SATOT(debug_mast,
				&ixs->outgoing_said, 0,
				ixs->sa_txt, sizeof(ixs->sa_txt));

		KLIPS_PRINT(debug_mast,
			    "klips_debug:ipsec_mast_check_outbound_policy: "
			    "SA:%s, inner tunnel policy [%s -> %s] agrees with pkt contents [%s -> %s].\n",
			    ixs->sa_len ? ixs->sa_txt : " (error)",
			    sflow_txt, dflow_txt, saddr_txt, daddr_txt);
	}
#endif

	return 0;
}
コード例 #8
0
ファイル: ipsec_sa.c プロジェクト: yottanami/libreswan
int ipsec_sa_wipe(struct ipsec_sa *ips)
{
	int hashval;
	struct ipsec_sa **tpp;

	if (ips == NULL)
		return -ENODATA;

#if IPSEC_SA_REF_CODE
	/* remove me from the SArefTable */
	if (debug_xform) {
		char sa[SATOT_BUF];
		size_t sa_len;
		struct IPsecSArefSubTable *subtable = NULL;

		if (IPsecSAref2table(IPsecSA2SAref(ips)) <
		    IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES &&
		    ipsec_sadb.refTable != NULL)
			subtable = ipsec_sadb.refTable[
				IPsecSAref2table(IPsecSA2SAref(ips))];

		sa_len = KLIPS_SATOT(debug_xform, &ips->ips_said, 0, sa,
				     sizeof(sa));
		KLIPS_PRINT(debug_xform,
			    "klips_debug:ipsec_sa_wipe: "
			    "removing SA=%s(0p%p), SAref=%d, table=%d(0p%p), entry=%d from the refTable.\n",
			    sa_len ? sa : " (error)",
			    ips,
			    ips->ips_ref,
			    IPsecSAref2table(IPsecSA2SAref(ips)),
			    subtable,
			    subtable ? IPsecSAref2entry(IPsecSA2SAref(ips)) : 0);
	}

	if (ips->ips_ref != IPSEC_SAREF_NULL) {
		struct IPsecSArefSubTable *subtable = NULL;
		int ref_table = IPsecSAref2table(IPsecSA2SAref(ips));
		int ref_entry = IPsecSAref2entry(IPsecSA2SAref(ips));

		if (ref_table < IPSEC_SA_REF_SUBTABLE_NUM_ENTRIES) {
			subtable = ipsec_sadb.refTable[ref_table];
			if (subtable != NULL && subtable->entry[ref_entry] ==
			    ips) {

				subtable->entry[ref_entry] = NULL;
			}
		}
		ips->ips_ref = IPSEC_SAREF_NULL;
	}
#endif  /* IPSEC_SA_REF_CODE */

	/* paranoid clean up */
	if (ips->ips_addr_s != NULL) {
		memset((caddr_t)(ips->ips_addr_s), 0, ips->ips_addr_s_size);
		kfree(ips->ips_addr_s);
	}
	ips->ips_addr_s = NULL;

	if (ips->ips_addr_d != NULL) {
		memset((caddr_t)(ips->ips_addr_d), 0, ips->ips_addr_d_size);
		kfree(ips->ips_addr_d);
	}
	ips->ips_addr_d = NULL;

	if (ips->ips_addr_p != NULL) {
		memset((caddr_t)(ips->ips_addr_p), 0, ips->ips_addr_p_size);
		kfree(ips->ips_addr_p);
	}
	ips->ips_addr_p = NULL;

	if (ips->ips_natt_oa) {
		memset((caddr_t)(ips->ips_natt_oa), 0, ips->ips_natt_oa_size);
		kfree(ips->ips_natt_oa);
	}
	ips->ips_natt_oa = NULL;

	if (ips->ips_key_a != NULL) {
#ifdef CONFIG_KLIPS_ALG
		if (ips->ips_alg_auth &&
		    ips->ips_alg_auth->ixt_a_destroy_key)
		{
			ips->ips_alg_auth->ixt_a_destroy_key(ips->ips_alg_auth, 
							     ips->ips_key_a);
		} else
#endif
		{
			memset((caddr_t)(ips->ips_key_a), 0, ips->ips_key_a_size);
			kfree(ips->ips_key_a);
		}
	}
	ips->ips_key_a = NULL;

	if (ips->ips_key_e != NULL) {
#ifdef CONFIG_KLIPS_ALG
		if (ips->ips_alg_enc &&
		    ips->ips_alg_enc->ixt_e_destroy_key) {
			ips->ips_alg_enc->ixt_e_destroy_key(ips->ips_alg_enc,
							    ips->ips_key_e);
		} else
#endif
		{
			memset((caddr_t)(ips->ips_key_e), 0,
			       ips->ips_key_e_size);
			kfree(ips->ips_key_e);
		}
	}
	ips->ips_key_e = NULL;

	if (ips->ips_iv != NULL) {
		memset((caddr_t)(ips->ips_iv), 0, ips->ips_iv_size);
		kfree(ips->ips_iv);
	}
	ips->ips_iv = NULL;

#ifdef CONFIG_KLIPS_OCF
	if (ips->ocf_in_use)
		ipsec_ocf_sa_free(ips);
#endif

	if (ips->ips_ident_s.data != NULL) {
		memset((caddr_t)(ips->ips_ident_s.data),
		       0,
		       ips->ips_ident_s.len * IPSEC_PFKEYv2_ALIGN -
		       sizeof(struct sadb_ident));
		kfree(ips->ips_ident_s.data);
	}
	ips->ips_ident_s.data = NULL;

	if (ips->ips_ident_d.data != NULL) {
		memset((caddr_t)(ips->ips_ident_d.data),
		       0,
		       ips->ips_ident_d.len * IPSEC_PFKEYv2_ALIGN -
		       sizeof(struct sadb_ident));
		kfree(ips->ips_ident_d.data);
	}
	ips->ips_ident_d.data = NULL;

#ifdef CONFIG_KLIPS_ALG
	if (ips->ips_alg_enc || ips->ips_alg_auth)
		ipsec_alg_sa_wipe(ips);
	ips->ips_alg_enc = NULL;
	ips->ips_alg_auth = NULL;

#endif
	if (ips->ips_prev)
		ips->ips_prev->ips_next = ips->ips_next;
	if (ips->ips_next) {
		ips->ips_next->ips_prev = ips->ips_prev;
		ipsec_sa_put(ips->ips_next, IPSEC_REFALLOC);
	}
	ips->ips_next = NULL;
	ips->ips_prev = NULL;

	hashval = IPS_HASH(&ips->ips_said);
	tpp = &ipsec_sadb_hash[hashval];
	while (*tpp) {
		if (*tpp == ips)
			*tpp = ips->ips_hnext;
		else
			tpp = &((*tpp)->ips_hnext);
	}
	if (ips->ips_hnext)
		ipsec_sa_put(ips->ips_hnext, IPSEC_REFALLOC);
	ips->ips_hnext = NULL;

	BUG_ON(atomic_read(&ips->ips_refcount) != 0);

#ifdef IPSEC_SA_RECOUNT_DEBUG
	if (ips == ipsec_sa_raw) {
		ipsec_sa_raw = ips->ips_raw;
	} else {
		struct ipsec_sa *raw = ipsec_sa_raw;
		while (raw) {
			if (raw->ips_raw == ips) {
				raw->ips_raw = ips->ips_raw;
				break;
			}
			raw = raw->ips_raw;
		}
	}
#endif
	if (ips->ips_out != NULL) {
		ipsec_dev_put(ips->ips_out);
		ips->ips_out = NULL;
	}

	memset((caddr_t)ips, 0, sizeof(*ips));
	kfree(ips);
	ips = NULL;

	return 0;
}
コード例 #9
0
ファイル: ipsec_sa.c プロジェクト: yottanami/libreswan
/*
 * The ipsec_sa table better be locked before it is handed in,
 * or races might happen.
 *
 * this routine assumes the SA has a refcount==0, and we free it.
 * we also assume that the pointers are already cleaned up.
 */
static int ipsec_sa_del(struct ipsec_sa *ips)
{
	unsigned int hashval;
	struct ipsec_sa *ipstp;
	char sa[SATOT_BUF];
	size_t sa_len;

	if (ips == NULL) {
		KLIPS_ERROR(debug_xform,
			    "klips_error:ipsec_sa_del: "
			    "null pointer passed in!\n");
		return -ENODATA;
	}

	if (ips->ips_next) {
		struct ipsec_sa *in = ips->ips_next;

		ips->ips_next = NULL;
		ipsec_sa_put(in);
	}

	sa_len = KLIPS_SATOT(debug_xform, &ips->ips_said, 0, sa, sizeof(sa));
	hashval = IPS_HASH(&ips->ips_said);

	KLIPS_PRINT(debug_xform,
		    "klips_debug:ipsec_sa_del: "
		    "deleting SA:%s (ref=%u), hashval=%d.\n",
		    sa_len ? sa : " (error)",
		    ips->ips_ref,
		    hashval);

	if (ipsec_sadb_hash[hashval] == NULL) {
		/* if this is NULL, then we can be sure that the SA was never
		 * added to the SADB, so we just free it.
		 */
		KLIPS_PRINT(debug_xform,
			    "klips_debug:ipsec_sa_del: "
			    "no entries in ipsec_sa table for hash=%d (ref=%u) of SA:%s.\n",
			    hashval,
			    ips->ips_ref,
			    sa_len ? sa : " (error)");
		return -ENOENT;
	}

	if (ips == ipsec_sadb_hash[hashval]) {
		ipsec_sadb_hash[hashval] = ipsec_sadb_hash[hashval]->ips_hnext;
		ips->ips_hnext = NULL;

		ipsec_sa_put(ips);
		KLIPS_PRINT(debug_xform,
			    "klips_debug:ipsec_sa_del: "
			    "successfully deleted first ipsec_sa in chain.\n");
		return 0;
	} else {
		for (ipstp = ipsec_sadb_hash[hashval];
		     ipstp;
		     ipstp = ipstp->ips_hnext) {
			if (ipstp->ips_hnext == ips) {
				ipstp->ips_hnext = ips->ips_hnext;
				ips->ips_hnext = NULL;
				ipsec_sa_put(ips);
				KLIPS_PRINT(debug_xform,
					    "klips_debug:ipsec_sa_del: "
					    "successfully deleted link in ipsec_sa chain.\n");
				return 0;
			}
		}
	}

	KLIPS_PRINT(debug_xform,
		    "klips_debug:ipsec_sa_del: "
		    "no entries in linked list for hash=%d of SA:%s.\n",
		    hashval,
		    sa_len ? sa : " (error)");
	return -ENOENT;
}
コード例 #10
0
ファイル: ipsec_sa.c プロジェクト: yottanami/libreswan
int ipsec_sa_init(struct ipsec_sa *ipsp)
{
	int error = 0;
	char sa[SATOT_BUF];
	size_t sa_len;

#ifdef CONFIG_KLIPS_DEBUG
	char ipaddr_txt[ADDRTOA_BUF];
	char ipaddr2_txt[ADDRTOA_BUF];
#endif
#if defined (CONFIG_KLIPS_AUTH_HMAC_MD5) || \
	defined (CONFIG_KLIPS_AUTH_HMAC_SHA1)
	unsigned char kb[AHMD596_BLKLEN];
	int i;
#endif

	if (ipsp == NULL) {
		KLIPS_PRINT(debug_pfkey,
			    "ipsec_sa_init: "
			    "ipsp is NULL, fatal\n");
		SENDERR(EINVAL);
	}

	sa_len = KLIPS_SATOT(debug_pfkey, &ipsp->ips_said, 0, sa, sizeof(sa));

	KLIPS_PRINT(debug_pfkey,
		    "ipsec_sa_init: "
		    "(pfkey defined) called for SA:%s\n",
		    sa_len ? sa : " (error)");

	KLIPS_PRINT(debug_pfkey,
		    "ipsec_sa_init: "
		    "calling init routine of %s%s%s\n",
		    IPS_XFORM_NAME(ipsp));

	switch (ipsp->ips_said.proto) {
#ifdef CONFIG_KLIPS_IPIP
	case IPPROTO_IPIP: {
		ipsp->ips_xformfuncs = ipip_xform_funcs;
#ifdef CONFIG_KLIPS_DEBUG
		sin_addrtot(ipsp->ips_addr_s, 0, ipaddr_txt,
			    sizeof(ipaddr_txt));
		sin_addrtot(ipsp->ips_addr_d, 0, ipaddr2_txt,
			    sizeof(ipaddr2_txt));
		KLIPS_PRINT(debug_pfkey,
			    "ipsec_sa_init: "
			    "(pfkey defined) IPIP ipsec_sa set for %s->%s.\n",
			    ipaddr_txt,
			    ipaddr2_txt);
#endif
	}
	break;
#endif          /* !CONFIG_KLIPS_IPIP */

#ifdef CONFIG_KLIPS_AH
	case IPPROTO_AH:

		ipsp->ips_xformfuncs = ah_xform_funcs;

#ifdef CONFIG_KLIPS_OCF
		if (ipsec_ocf_sa_init(ipsp, ipsp->ips_authalg, 0))
			break;
#endif

#ifdef CONFIG_KLIPS_ALG
		error = ipsec_alg_auth_key_create(ipsp);
		if ((error < 0) && (error != -EPROTO))
			SENDERR(-error);

		if (error == -EPROTO) {
			/* perform manual key generation,
			   ignore this particular error */
			error = 0;
#endif              /* CONFIG_KLIPS_ALG */

		switch (ipsp->ips_authalg) {
# ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
		case AH_MD5: {
			unsigned char *akp;
			unsigned int aks;
			MD5_CTX *ictx;
			MD5_CTX *octx;

			if (ipsp->ips_key_bits_a != (AHMD596_KLEN * 8)) {
				KLIPS_PRINT(debug_pfkey,
					    "ipsec_sa_init: "
					    "incorrect key size: %d bits -- must be %d bits\n" /*octets (bytes)\n"*/,
					    ipsp->ips_key_bits_a, AHMD596_KLEN *
					    8);
				SENDERR(EINVAL);
			}

#  if KLIPS_DIVULGE_HMAC_KEY
			KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
				    "ipsec_sa_init: "
				    "hmac md5-96 key is 0x%08x %08x %08x %08x\n",
				    ntohl(*(((__u32 *)ipsp->ips_key_a) + 0)),
				    ntohl(*(((__u32 *)ipsp->ips_key_a) + 1)),
				    ntohl(*(((__u32 *)ipsp->ips_key_a) + 2)),
				    ntohl(*(((__u32 *)ipsp->ips_key_a) + 3)));
#  endif                        /* KLIPS_DIVULGE_HMAC_KEY */

			ipsp->ips_auth_bits = AHMD596_ALEN * 8;

			/* save the pointer to the key material */
			akp = ipsp->ips_key_a;
			aks = ipsp->ips_key_a_size;

			KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
				    "ipsec_sa_init: "
				    "allocating %lu bytes for md5_ctx.\n",
				    (unsigned long) sizeof(struct md5_ctx));
			if ((ipsp->ips_key_a = (caddr_t)
					       kmalloc(sizeof(struct md5_ctx),
						       GFP_ATOMIC)) == NULL) {
				ipsp->ips_key_a = akp;
				SENDERR(ENOMEM);
			}
			ipsp->ips_key_a_size = sizeof(struct md5_ctx);

			for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++)
				kb[i] = akp[i] ^ HMAC_IPAD;
			for (; i < AHMD596_BLKLEN; i++)
				kb[i] = HMAC_IPAD;

			ictx = &(((struct md5_ctx*)(ipsp->ips_key_a))->ictx);
			osMD5Init(ictx);
			osMD5Update(ictx, kb, AHMD596_BLKLEN);

			for (i = 0; i < AHMD596_BLKLEN; i++)
				kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);

			octx = &(((struct md5_ctx*)(ipsp->ips_key_a))->octx);
			osMD5Init(octx);
			osMD5Update(octx, kb, AHMD596_BLKLEN);

#  if KLIPS_DIVULGE_HMAC_KEY
			KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
				    "ipsec_sa_init: "
				    "MD5 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
				    ((__u32*)ictx)[0],
				    ((__u32*)ictx)[1],
				    ((__u32*)ictx)[2],
				    ((__u32*)ictx)[3],
				    ((__u32*)octx)[0],
				    ((__u32*)octx)[1],
				    ((__u32*)octx)[2],
				    ((__u32*)octx)[3] );
#  endif                        /* KLIPS_DIVULGE_HMAC_KEY */

			/* zero key buffer -- paranoid */
			memset(akp, 0, aks);
			kfree(akp);
		}
		break;
# endif                 /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
# ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
		case AH_SHA: {
			unsigned char *akp;
			unsigned int aks;
			SHA1_CTX *ictx;
			SHA1_CTX *octx;

			if (ipsp->ips_key_bits_a != (AHSHA196_KLEN * 8)) {
				KLIPS_PRINT(debug_pfkey,
					    "ipsec_sa_init: "
					    "incorrect key size: %d bits -- must be %d bits\n" /*octets (bytes)\n"*/,
					    ipsp->ips_key_bits_a, AHSHA196_KLEN *
					    8);
				SENDERR(EINVAL);
			}

#  if KLIPS_DIVULGE_HMAC_KEY
			KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
				    "ipsec_sa_init: "
				    "hmac sha1-96 key is 0x%08x %08x %08x %08x\n",
				    ntohl(*(((__u32 *)ipsp->ips_key_a) + 0)),
				    ntohl(*(((__u32 *)ipsp->ips_key_a) + 1)),
				    ntohl(*(((__u32 *)ipsp->ips_key_a) + 2)),
				    ntohl(*(((__u32 *)ipsp->ips_key_a) + 3)));
#  endif                        /* KLIPS_DIVULGE_HMAC_KEY */

			ipsp->ips_auth_bits = AHSHA196_ALEN * 8;

			/* save the pointer to the key material */
			akp = ipsp->ips_key_a;
			aks = ipsp->ips_key_a_size;

			KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
				    "ipsec_sa_init: "
				    "allocating %lu bytes for sha1_ctx.\n",
				    (unsigned long) sizeof(struct sha1_ctx));
			if ((ipsp->ips_key_a = (caddr_t)
					       kmalloc(sizeof(struct sha1_ctx),
						       GFP_ATOMIC)) == NULL) {
				ipsp->ips_key_a = akp;
				SENDERR(ENOMEM);
			}
			ipsp->ips_key_a_size = sizeof(struct sha1_ctx);

			for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8); i++)
				kb[i] = akp[i] ^ HMAC_IPAD;
			for (; i < AHMD596_BLKLEN; i++)
				kb[i] = HMAC_IPAD;

			ictx = &(((struct sha1_ctx*)(ipsp->ips_key_a))->ictx);
			SHA1Init(ictx);
			SHA1Update(ictx, kb, AHSHA196_BLKLEN);

			for (i = 0; i < AHSHA196_BLKLEN; i++)
				kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);

			octx = &(((struct sha1_ctx*)(ipsp->ips_key_a))->octx);
			SHA1Init(octx);
			SHA1Update(octx, kb, AHSHA196_BLKLEN);

#  if KLIPS_DIVULGE_HMAC_KEY
			KLIPS_PRINT(debug_pfkey && sysctl_ipsec_debug_verbose,
				    "ipsec_sa_init: "
				    "SHA1 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
				    ((__u32*)ictx)[0],
				    ((__u32*)ictx)[1],
				    ((__u32*)ictx)[2],
				    ((__u32*)ictx)[3],
				    ((__u32*)octx)[0],
				    ((__u32*)octx)[1],
				    ((__u32*)octx)[2],
				    ((__u32*)octx)[3] );
#  endif                        /* KLIPS_DIVULGE_HMAC_KEY */
			/* zero key buffer -- paranoid */
			memset(akp, 0, aks);
			kfree(akp);
		}
		break;
# endif                 /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
		default:
			KLIPS_PRINT(debug_pfkey,
				    "ipsec_sa_init: "
				    "authalg=%d support not available in the kernel",
				    ipsp->ips_authalg);
			SENDERR(EINVAL);
		}
#ifdef CONFIG_KLIPS_ALG
			/* closure of the -EPROTO condition above */
		}
#endif
		break;
#endif          /* CONFIG_KLIPS_AH */

#ifdef CONFIG_KLIPS_ESP
	case IPPROTO_ESP:
		ipsp->ips_xformfuncs = esp_xform_funcs;
		{
#ifdef CONFIG_KLIPS_OCF
			if (ipsec_ocf_sa_init(ipsp, ipsp->ips_authalg,
					      ipsp->ips_encalg))
				break;
#endif

#ifdef CONFIG_KLIPS_ALG
			error = ipsec_alg_enc_key_create(ipsp);
			if (error < 0)
				SENDERR(-error);

			error = ipsec_alg_auth_key_create(ipsp);
			if ((error < 0) && (error != -EPROTO))
				SENDERR(-error);

			if (error == -EPROTO) {
				/* perform manual key generation,
				   ignore this particular error */
				error = 0;
#endif                  /* CONFIG_KLIPS_ALG */

			switch (ipsp->ips_authalg) {
#if defined (CONFIG_KLIPS_AUTH_HMAC_MD5) || \
				defined (CONFIG_KLIPS_AUTH_HMAC_SHA1)
				unsigned char *akp;
				unsigned int aks;
#endif
# ifdef CONFIG_KLIPS_AUTH_HMAC_MD5
			case AH_MD5: {
				MD5_CTX *ictx;
				MD5_CTX *octx;

				if (ipsp->ips_key_bits_a !=
				    (AHMD596_KLEN * 8)) {
					KLIPS_PRINT(debug_pfkey,
						    "ipsec_sa_init: "
						    "incorrect authorisation key size: %d bits -- must be %d bits\n" /*octets (bytes)\n"*/,
						    ipsp->ips_key_bits_a,
						    AHMD596_KLEN * 8);
					SENDERR(EINVAL);
				}

#  if KLIPS_DIVULGE_HMAC_KEY
				KLIPS_PRINT(
					debug_pfkey && sysctl_ipsec_debug_verbose,
					"ipsec_sa_init: "
					"hmac md5-96 key is 0x%08x %08x %08x %08x\n",
					ntohl(*(((__u32 *)(ipsp->ips_key_a)) +
						0)),
					ntohl(*(((__u32 *)(ipsp->ips_key_a)) +
						1)),
					ntohl(*(((__u32 *)(ipsp->ips_key_a)) +
						2)),
					ntohl(*(((__u32 *)(ipsp->ips_key_a)) +
						3)));
#  endif                                /* KLIPS_DIVULGE_HMAC_KEY */
				ipsp->ips_auth_bits = AHMD596_ALEN * 8;

				/* save the pointer to the key material */
				akp = ipsp->ips_key_a;
				aks = ipsp->ips_key_a_size;

				KLIPS_PRINT(
					debug_pfkey && sysctl_ipsec_debug_verbose,
					"ipsec_sa_init: "
					"allocating %lu bytes for md5_ctx.\n",
					(unsigned long) sizeof(struct
							       md5_ctx));
				if ((ipsp->ips_key_a = (caddr_t)
					kmalloc(sizeof(struct md5_ctx),
						GFP_ATOMIC)) == NULL) {
					ipsp->ips_key_a = akp;
					SENDERR(ENOMEM);
				}
				ipsp->ips_key_a_size = sizeof(struct md5_ctx);

				for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8);
				     i++)
					kb[i] = akp[i] ^ HMAC_IPAD;
				for (; i < AHMD596_BLKLEN; i++)
					kb[i] = HMAC_IPAD;

				ictx = &(((struct md5_ctx*)(ipsp->ips_key_a))
					  ->ictx);
				osMD5Init(ictx);
				osMD5Update(ictx, kb, AHMD596_BLKLEN);

				for (i = 0; i < AHMD596_BLKLEN; i++)
					kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);

				octx = &(((struct md5_ctx*)(ipsp->ips_key_a))
					  ->octx);
				osMD5Init(octx);
				osMD5Update(octx, kb, AHMD596_BLKLEN);

#  if KLIPS_DIVULGE_HMAC_KEY
				KLIPS_PRINT(
					debug_pfkey && sysctl_ipsec_debug_verbose,
					"ipsec_sa_init: "
					"MD5 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
					((__u32*)ictx)[0],
					((__u32*)ictx)[1],
					((__u32*)ictx)[2],
					((__u32*)ictx)[3],
					((__u32*)octx)[0],
					((__u32*)octx)[1],
					((__u32*)octx)[2],
					((__u32*)octx)[3] );
#  endif                                /* KLIPS_DIVULGE_HMAC_KEY */
				/* paranoid */
				memset(akp, 0, aks);
				kfree(akp);
				break;
			}
# endif                         /* CONFIG_KLIPS_AUTH_HMAC_MD5 */
# ifdef CONFIG_KLIPS_AUTH_HMAC_SHA1
			case AH_SHA: {
				SHA1_CTX *ictx;
				SHA1_CTX *octx;

				if (ipsp->ips_key_bits_a !=
				    (AHSHA196_KLEN * 8)) {
					KLIPS_PRINT(debug_pfkey,
						    "ipsec_sa_init: "
						    "incorrect authorisation key size: %d bits -- must be %d bits\n" /*octets (bytes)\n"*/,
						    ipsp->ips_key_bits_a,
						    AHSHA196_KLEN * 8);
					SENDERR(EINVAL);
				}

#  if KLIPS_DIVULGE_HMAC_KEY
				KLIPS_PRINT(
					debug_pfkey && sysctl_ipsec_debug_verbose,
					"ipsec_sa_init: "
					"hmac sha1-96 key is 0x%08x %08x %08x %08x\n",
					ntohl(*(((__u32 *)ipsp->ips_key_a) +
						0)),
					ntohl(*(((__u32 *)ipsp->ips_key_a) +
						1)),
					ntohl(*(((__u32 *)ipsp->ips_key_a) +
						2)),
					ntohl(*(((__u32 *)ipsp->ips_key_a) +
						3)));
#  endif                                /* KLIPS_DIVULGE_HMAC_KEY */
				ipsp->ips_auth_bits = AHSHA196_ALEN * 8;

				/* save the pointer to the key material */
				akp = ipsp->ips_key_a;
				aks = ipsp->ips_key_a_size;

				KLIPS_PRINT(
					debug_pfkey && sysctl_ipsec_debug_verbose,
					"ipsec_sa_init: "
					"allocating %lu bytes for sha1_ctx.\n",
					(unsigned long) sizeof(struct
							       sha1_ctx));
				if ((ipsp->ips_key_a = (caddr_t)
					kmalloc(sizeof(struct sha1_ctx),
						GFP_ATOMIC)) == NULL) {
					ipsp->ips_key_a = akp;
					SENDERR(ENOMEM);
				}
				ipsp->ips_key_a_size = sizeof(struct sha1_ctx);

				for (i = 0; i < DIVUP(ipsp->ips_key_bits_a, 8);
				     i++)
					kb[i] = akp[i] ^ HMAC_IPAD;
				for (; i < AHMD596_BLKLEN; i++)
					kb[i] = HMAC_IPAD;

				ictx = &(((struct sha1_ctx*)(ipsp->ips_key_a))
					  ->ictx);
				SHA1Init(ictx);
				SHA1Update(ictx, kb, AHSHA196_BLKLEN);

				for (i = 0; i < AHSHA196_BLKLEN; i++)
					kb[i] ^= (HMAC_IPAD ^ HMAC_OPAD);

				octx = &((struct sha1_ctx*)(ipsp->ips_key_a))
					->octx;
				SHA1Init(octx);
				SHA1Update(octx, kb, AHSHA196_BLKLEN);

#  if KLIPS_DIVULGE_HMAC_KEY
				KLIPS_PRINT(
					debug_pfkey && sysctl_ipsec_debug_verbose,
					"ipsec_sa_init: "
					"SHA1 ictx=0x%08x %08x %08x %08x octx=0x%08x %08x %08x %08x\n",
					((__u32*)ictx)[0],
					((__u32*)ictx)[1],
					((__u32*)ictx)[2],
					((__u32*)ictx)[3],
					((__u32*)octx)[0],
					((__u32*)octx)[1],
					((__u32*)octx)[2],
					((__u32*)octx)[3] );
#  endif                                /* KLIPS_DIVULGE_HMAC_KEY */
				memset(akp, 0, aks);
				kfree(akp);
				break;
			}
# endif                         /* CONFIG_KLIPS_AUTH_HMAC_SHA1 */
			case AH_NONE:
				break;
			default:
				KLIPS_PRINT(debug_pfkey,
					    "ipsec_sa_init: "
					    "authalg=%d support not available in the kernel.\n",
					    ipsp->ips_authalg);
				SENDERR(EINVAL);
			}
#ifdef CONFIG_KLIPS_ALG
			/* closure of the -EPROTO condition above */
		}
#endif

			ipsp->ips_iv_size =
				ipsp->ips_alg_enc->ixt_common.ixt_support.
				ias_ivlen / 8;

			/* Create IV */
			if (ipsp->ips_iv_size) {
				if ((ipsp->ips_iv = (caddr_t)
					kmalloc(ipsp->ips_iv_size,
						GFP_ATOMIC)) == NULL)
					SENDERR(ENOMEM);
				prng_bytes(&ipsec_prng, (char *)ipsp->ips_iv,
					   ipsp->ips_iv_size);
				ipsp->ips_iv_bits = ipsp->ips_iv_size * 8;
			}
		}
		break;
#endif          /* !CONFIG_KLIPS_ESP */
#ifdef CONFIG_KLIPS_IPCOMP
	case IPPROTO_COMP:

		ipsp->ips_xformfuncs = ipcomp_xform_funcs;

		ipsp->ips_comp_adapt_tries = 0;
		ipsp->ips_comp_adapt_skip = 0;
		ipsp->ips_comp_ratio_cbytes = 0;
		ipsp->ips_comp_ratio_dbytes = 0;

#ifdef CONFIG_KLIPS_OCF
		if (ipsec_ocf_comp_sa_init(ipsp, ipsp->ips_encalg))
			break;
#endif

		ipsp->ips_comp_adapt_tries = 0;
		ipsp->ips_comp_adapt_skip = 0;
		ipsp->ips_comp_ratio_cbytes = 0;
		ipsp->ips_comp_ratio_dbytes = 0;
		break;
#endif          /* CONFIG_KLIPS_IPCOMP */
	default:
		printk(KERN_ERR "KLIPS sa initialization: "
		       "proto=%d unknown.\n",
		       ipsp->ips_said.proto);
		SENDERR(EINVAL);
	}

errlab:
	return error;
}