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; }
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; }
/* * 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; } } } }
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; }
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; }
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; }
/* * 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; }
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; }
/* * 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; }
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; }