diff options
Diffstat (limited to 'linux/net/ipsec/ipsec_proc.c')
-rw-r--r-- | linux/net/ipsec/ipsec_proc.c | 1003 |
1 files changed, 1003 insertions, 0 deletions
diff --git a/linux/net/ipsec/ipsec_proc.c b/linux/net/ipsec/ipsec_proc.c new file mode 100644 index 000000000..5d2bba554 --- /dev/null +++ b/linux/net/ipsec/ipsec_proc.c @@ -0,0 +1,1003 @@ +/* + * @(#) /proc file system interface code. + * + * Copyright (C) 1996, 1997 John Ioannidis. + * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs <rgb@freeswan.org> + * 2001 Michael Richardson <mcr@freeswan.org> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * for more details. + * + * Split out from ipsec_init.c version 1.70. + */ + +char ipsec_proc_c_version[] = "RCSID $Id: ipsec_proc.c,v 1.8 2004/04/28 08:06:22 as Exp $"; + +#include <linux/config.h> +#include <linux/version.h> +#define __NO_VERSION__ +#include <linux/module.h> +#include <linux/kernel.h> /* printk() */ + +#include "freeswan/ipsec_param.h" + +#ifdef MALLOC_SLAB +# include <linux/slab.h> /* kmalloc() */ +#else /* MALLOC_SLAB */ +# include <linux/malloc.h> /* kmalloc() */ +#endif /* MALLOC_SLAB */ +#include <linux/errno.h> /* error codes */ +#include <linux/types.h> /* size_t */ +#include <linux/interrupt.h> /* mark_bh */ + +#include <linux/netdevice.h> /* struct device, and other headers */ +#include <linux/etherdevice.h> /* eth_type_trans */ +#include <linux/ip.h> /* struct iphdr */ +#include <linux/in.h> /* struct sockaddr_in */ +#include <linux/skbuff.h> +#include <freeswan.h> +#ifdef SPINLOCK +#ifdef SPINLOCK_23 +#include <linux/spinlock.h> /* *lock* */ +#else /* SPINLOCK_23 */ +#include <asm/spinlock.h> /* *lock* */ +#endif /* SPINLOCK_23 */ +#endif /* SPINLOCK */ +#ifdef NET_21 +#include <asm/uaccess.h> +#include <linux/in6.h> +#endif /* NET_21 */ +#include <asm/checksum.h> +#include <net/ip.h> +#ifdef CONFIG_PROC_FS +#include <linux/proc_fs.h> +#endif /* CONFIG_PROC_FS */ +#ifdef NETLINK_SOCK +#include <linux/netlink.h> +#else +#include <net/netlink.h> +#endif + +#include "freeswan/radij.h" + +#include "freeswan/ipsec_life.h" +#include "freeswan/ipsec_stats.h" +#include "freeswan/ipsec_sa.h" + +#include "freeswan/ipsec_encap.h" +#include "freeswan/ipsec_radij.h" +#include "freeswan/ipsec_xform.h" +#include "freeswan/ipsec_tunnel.h" +#include "freeswan/ipsec_xmit.h" + +#include "freeswan/ipsec_rcv.h" +#include "freeswan/ipsec_ah.h" +#include "freeswan/ipsec_esp.h" + +#ifdef CONFIG_IPSEC_IPCOMP +#include "freeswan/ipcomp.h" +#endif /* CONFIG_IPSEC_IPCOMP */ + +#include "freeswan/ipsec_proto.h" + +#include <pfkeyv2.h> +#include <pfkey.h> + +#ifdef CONFIG_PROC_FS + +#ifdef IPSEC_PROC_SUBDIRS +static struct proc_dir_entry *proc_net_ipsec_dir = NULL; +static struct proc_dir_entry *proc_eroute_dir = NULL; +static struct proc_dir_entry *proc_spi_dir = NULL; +static struct proc_dir_entry *proc_spigrp_dir = NULL; +static struct proc_dir_entry *proc_birth_dir = NULL; +static struct proc_dir_entry *proc_stats_dir = NULL; +#endif + +struct ipsec_birth_reply ipsec_ipv4_birth_packet; +struct ipsec_birth_reply ipsec_ipv6_birth_packet; + +extern int ipsec_xform_get_info(char *buffer, char **start, + off_t offset, int length IPSEC_PROC_LAST_ARG); + + +/* ipsec_snprintf: like snprintf except + * - size is signed and a negative value is treated as if it were 0 + * - the returned result is never negative -- + * an error generates a "?" or null output (depending on space). + * (Our callers are too lazy to check for an error return.) + * + * @param buf String buffer + * @param size Size of the string + * @param fmt printf string + * @param ... Variables to be displayed in fmt + * @return int Return code + */ +int ipsec_snprintf(char *buf, ssize_t size, const char *fmt, ...) +{ + va_list args; + int i; + size_t possize = size < 0? 0 : size; + va_start(args, fmt); + i = vsnprintf(buf,possize,fmt,args); + va_end(args); + if (i < 0) { + /* create empty output in place of error */ + i = 0; + if (size > 0) { + *buf = '\0'; + } + } + return i; +} + + +IPSEC_PROCFS_DEBUG_NO_STATIC +int +ipsec_eroute_get_info(char *buffer, + char **start, + off_t offset, + int length IPSEC_PROC_LAST_ARG) +{ + struct wsbuf w = {buffer, length, offset, 0, 0}; + +#ifdef CONFIG_IPSEC_DEBUG + if (debug_radij & DB_RJ_DUMPTREES) + rj_dumptrees(); /* XXXXXXXXX */ +#endif /* CONFIG_IPSEC_DEBUG */ + + KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS, + "klips_debug:ipsec_eroute_get_info: " + "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n", + buffer, + *start, + (int)offset, + length); + + spin_lock_bh(&eroute_lock); + + rj_walktree(rnh, ipsec_rj_walker_procprint, &w); +/* rj_walktree(mask_rjhead, ipsec_rj_walker_procprint, &w); */ + + spin_unlock_bh(&eroute_lock); + + *start = buffer + (offset - w.begin); /* Start of wanted data */ + return w.len - (offset - w.begin); +} + +IPSEC_PROCFS_DEBUG_NO_STATIC +int +ipsec_spi_get_info(char *buffer, + char **start, + off_t offset, + int length IPSEC_PROC_LAST_ARG) +{ + /* Limit of useful snprintf output */ + const int max_content = length > 0? length-1 : 0; + + int len = 0; + off_t begin = 0; + int i; + struct ipsec_sa *sa_p; + char sa[SATOA_BUF]; + char buf_s[SUBNETTOA_BUF]; + char buf_d[SUBNETTOA_BUF]; + size_t sa_len; + + KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS, + "klips_debug:ipsec_spi_get_info: " + "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n", + buffer, + *start, + (int)offset, + length); + + spin_lock_bh(&tdb_lock); + + + + for (i = 0; i < SADB_HASHMOD; i++) { + for (sa_p = ipsec_sadb_hash[i]; + sa_p; + sa_p = sa_p->ips_hnext) { + atomic_inc(&sa_p->ips_refcount); + sa_len = satoa(sa_p->ips_said, 0, sa, SATOA_BUF); + len += ipsec_snprintf(buffer+len, length-len, "%s ", + sa_len ? sa : " (error)"); + + len += ipsec_snprintf(buffer+len, length-len, "%s%s%s", + IPS_XFORM_NAME(sa_p)); + + len += ipsec_snprintf(buffer+len, length-len, ": dir=%s", + (sa_p->ips_flags & EMT_INBOUND) ? + "in " : "out"); + + if(sa_p->ips_addr_s) { + addrtoa(((struct sockaddr_in*)(sa_p->ips_addr_s))->sin_addr, + 0, buf_s, sizeof(buf_s)); + len += ipsec_snprintf(buffer+len, length-len, " src=%s", + buf_s); + } + + if((sa_p->ips_said.proto == IPPROTO_IPIP) + && (sa_p->ips_flags & SADB_X_SAFLAGS_INFLOW)) { + subnettoa(sa_p->ips_flow_s.u.v4.sin_addr, + sa_p->ips_mask_s.u.v4.sin_addr, + 0, + buf_s, + sizeof(buf_s)); + + subnettoa(sa_p->ips_flow_d.u.v4.sin_addr, + sa_p->ips_mask_d.u.v4.sin_addr, + 0, + buf_d, + sizeof(buf_d)); + + len += ipsec_snprintf(buffer+len, length-len, " policy=%s->%s", + buf_s, buf_d); + } + + if(sa_p->ips_iv_bits) { + int j; + len += ipsec_snprintf(buffer+len, length-len, " iv_bits=%dbits iv=0x", + sa_p->ips_iv_bits); + + for(j = 0; j < sa_p->ips_iv_bits / 8; j++) { + len += ipsec_snprintf(buffer+len, length-len, "%02x", + (__u32)((__u8*)(sa_p->ips_iv))[j]); + } + } + + if(sa_p->ips_encalg || sa_p->ips_authalg) { + if(sa_p->ips_replaywin) { + len += ipsec_snprintf(buffer+len, length-len, " ooowin=%d", + sa_p->ips_replaywin); + } + if(sa_p->ips_errs.ips_replaywin_errs) { + len += ipsec_snprintf(buffer+len, length-len, " ooo_errs=%d", + sa_p->ips_errs.ips_replaywin_errs); + } + if(sa_p->ips_replaywin_lastseq) { + len += ipsec_snprintf(buffer+len, length-len, " seq=%d", + sa_p->ips_replaywin_lastseq); + } + if(sa_p->ips_replaywin_bitmap) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + len += ipsec_snprintf(buffer+len, length-len, " bit=0x%Lx", + sa_p->ips_replaywin_bitmap); +#else + len += ipsec_snprintf(buffer+len, length-len, " bit=0x%x%08x", + (__u32)(sa_p->ips_replaywin_bitmap >> 32), + (__u32)sa_p->ips_replaywin_bitmap); +#endif + } + if(sa_p->ips_replaywin_maxdiff) { + len += ipsec_snprintf(buffer+len, length-len, " max_seq_diff=%d", + sa_p->ips_replaywin_maxdiff); + } + } + if(sa_p->ips_flags & ~EMT_INBOUND) { + len += ipsec_snprintf(buffer+len, length-len, " flags=0x%x", + sa_p->ips_flags & ~EMT_INBOUND); + len += ipsec_snprintf(buffer+len, length-len, "<"); + /* flag printing goes here */ + len += ipsec_snprintf(buffer+len, length-len, ">"); + } + if(sa_p->ips_auth_bits) { + len += ipsec_snprintf(buffer+len, length-len, " alen=%d", + sa_p->ips_auth_bits); + } + if(sa_p->ips_key_bits_a) { + len += ipsec_snprintf(buffer+len, length-len, " aklen=%d", + sa_p->ips_key_bits_a); + } + if(sa_p->ips_errs.ips_auth_errs) { + len += ipsec_snprintf(buffer+len, length-len, " auth_errs=%d", + sa_p->ips_errs.ips_auth_errs); + } + if(sa_p->ips_key_bits_e) { + len += ipsec_snprintf(buffer+len, length-len, " eklen=%d", + sa_p->ips_key_bits_e); + } + if(sa_p->ips_errs.ips_encsize_errs) { + len += ipsec_snprintf(buffer+len, length-len, " encr_size_errs=%d", + sa_p->ips_errs.ips_encsize_errs); + } + if(sa_p->ips_errs.ips_encpad_errs) { + len += ipsec_snprintf(buffer+len, length-len, " encr_pad_errs=%d", + sa_p->ips_errs.ips_encpad_errs); + } + + len += ipsec_snprintf(buffer+len, length-len, " life(c,s,h)="); + + len += ipsec_lifetime_format(buffer + len, + length - len, + "alloc", + ipsec_life_countbased, + &sa_p->ips_life.ipl_allocations); + + len += ipsec_lifetime_format(buffer + len, + length - len, + "bytes", + ipsec_life_countbased, + &sa_p->ips_life.ipl_bytes); + + len += ipsec_lifetime_format(buffer + len, + length - len, + "addtime", + ipsec_life_timebased, + &sa_p->ips_life.ipl_addtime); + + len += ipsec_lifetime_format(buffer + len, + length - len, + "usetime", + ipsec_life_timebased, + &sa_p->ips_life.ipl_usetime); + + len += ipsec_lifetime_format(buffer + len, + length - len, + "packets", + ipsec_life_countbased, + &sa_p->ips_life.ipl_packets); + + if(sa_p->ips_life.ipl_usetime.ipl_last) { /* XXX-MCR should be last? */ +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + len += ipsec_snprintf(buffer+len, length-len, " idle=%Ld", + jiffies / HZ - sa_p->ips_life.ipl_usetime.ipl_last); +#else + len += ipsec_snprintf(buffer+len, length-len, " idle=%lu", + jiffies / HZ - (unsigned long)sa_p->ips_life.ipl_usetime.ipl_last); +#endif + } + +#ifdef CONFIG_IPSEC_IPCOMP + if(sa_p->ips_said.proto == IPPROTO_COMP && + (sa_p->ips_comp_ratio_dbytes || + sa_p->ips_comp_ratio_cbytes)) { +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0) + len += ipsec_snprintf(buffer+len, length-len, " ratio=%Ld:%Ld", + sa_p->ips_comp_ratio_dbytes, + sa_p->ips_comp_ratio_cbytes); +#else + len += ipsec_snprintf(buffer+len, length-len, " ratio=%lu:%lu", + (unsigned long)sa_p->ips_comp_ratio_dbytes, + (unsigned long)sa_p->ips_comp_ratio_cbytes); +#endif + } +#endif /* CONFIG_IPSEC_IPCOMP */ + +#ifdef CONFIG_IPSEC_NAT_TRAVERSAL + if(sa_p->ips_natt_type != 0) { + char *natttype_name; + + switch(sa_p->ips_natt_type) + { + case ESPINUDP_WITH_NON_IKE: + natttype_name="nonike"; + break; + case ESPINUDP_WITH_NON_ESP: + natttype_name="nonesp"; + break; + default: + natttype_name="unknown"; + break; + } + + len += ipsec_snprintf(buffer+len, length-len, " natencap=%s", + natttype_name); + + len += ipsec_snprintf(buffer+len, length-len, " natsport=%d", + sa_p->ips_natt_sport); + + len += ipsec_snprintf(buffer+len, length-len, " natdport=%d", + sa_p->ips_natt_dport); + } +#endif /* CONFIG_IPSEC_NAT_TRAVERSAL */ + + len += ipsec_snprintf(buffer+len, length-len, " refcount=%d", + atomic_read(&sa_p->ips_refcount)); + + len += ipsec_snprintf(buffer+len, length-len, " ref=%d", + sa_p->ips_ref); +#ifdef CONFIG_IPSEC_DEBUG + if(debug_xform) { + len += ipsec_snprintf(buffer+len, length-len, " reftable=%lu refentry=%lu", + (unsigned long)IPsecSAref2table(sa_p->ips_ref), + (unsigned long)IPsecSAref2entry(sa_p->ips_ref)); + } +#endif /* CONFIG_IPSEC_DEBUG */ + + len += ipsec_snprintf(buffer+len, length-len, "\n"); + + atomic_dec(&sa_p->ips_refcount); + + if (len >= max_content) { + /* we've done all that can fit -- stop loops */ + len = max_content; /* truncate crap */ + goto done_spi_i; + } else { + const off_t pos = begin + len; + + if (pos <= offset) { + /* all is before first interesting character: + * discard, but note where we are. + */ + len = 0; + begin = pos; + } + } + } + } + +done_spi_i: + spin_unlock_bh(&tdb_lock); + + *start = buffer + (offset - begin); /* Start of wanted data */ + return len - (offset - begin); +} + +IPSEC_PROCFS_DEBUG_NO_STATIC +int +ipsec_spigrp_get_info(char *buffer, + char **start, + off_t offset, + int length IPSEC_PROC_LAST_ARG) +{ + /* limit of useful snprintf output */ + const int max_content = length > 0? length-1 : 0; + + int len = 0; + off_t begin = 0; + int i; + struct ipsec_sa *sa_p, *sa_p2; + char sa[SATOA_BUF]; + size_t sa_len; + + KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS, + "klips_debug:ipsec_spigrp_get_info: " + "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n", + buffer, + *start, + (int)offset, + length); + + spin_lock_bh(&tdb_lock); + + for (i = 0; i < SADB_HASHMOD; i++) { + for (sa_p = ipsec_sadb_hash[i]; + sa_p != NULL; + sa_p = sa_p->ips_hnext) + { + atomic_inc(&sa_p->ips_refcount); + if(sa_p->ips_inext == NULL) { + sa_p2 = sa_p; + while(sa_p2 != NULL) { + atomic_inc(&sa_p2->ips_refcount); + sa_len = satoa(sa_p2->ips_said, + 0, sa, SATOA_BUF); + + len += ipsec_snprintf(buffer+len, length-len, "%s ", + sa_len ? sa : " (error)"); + atomic_dec(&sa_p2->ips_refcount); + sa_p2 = sa_p2->ips_onext; + } + len += ipsec_snprintf(buffer+len, length-len, "\n"); + } + + atomic_dec(&sa_p->ips_refcount); + + if (len >= max_content) { + /* we've done all that can fit -- stop loops */ + len = max_content; /* truncate crap */ + goto done_spigrp_i; + } else { + const off_t pos = begin + len; + + if (pos <= offset) { + /* all is before first interesting character: + * discard, but note where we are. + */ + len = 0; + begin = pos; + } + } + } + } + + done_spigrp_i: + spin_unlock_bh(&tdb_lock); + + *start = buffer + (offset - begin); /* Start of wanted data */ + return len - (offset - begin); +} + +IPSEC_PROCFS_DEBUG_NO_STATIC +int +ipsec_tncfg_get_info(char *buffer, + char **start, + off_t offset, + int length IPSEC_PROC_LAST_ARG) +{ + /* limit of useful snprintf output */ + const int max_content = length > 0? length-1 : 0; + + int len = 0; + off_t begin = 0; + int i; + char name[9]; + struct device *dev, *privdev; + struct ipsecpriv *priv; + + KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS, + "klips_debug:ipsec_tncfg_get_info: " + "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n", + buffer, + *start, + (int)offset, + length); + + for(i = 0; i < IPSEC_NUM_IF; i++) { + ipsec_snprintf(name, (ssize_t) sizeof(name), IPSEC_DEV_FORMAT, i); + dev = __ipsec_dev_get(name); + if(dev) { + priv = (struct ipsecpriv *)(dev->priv); + len += ipsec_snprintf(buffer+len, length-len, "%s", + dev->name); + if(priv) { + privdev = (struct device *)(priv->dev); + len += ipsec_snprintf(buffer+len, length-len, " -> %s", + privdev ? privdev->name : "NULL"); + len += ipsec_snprintf(buffer+len, length-len, " mtu=%d(%d) -> %d", + dev->mtu, + priv->mtu, + privdev ? privdev->mtu : 0); + } else { + KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS, + "klips_debug:ipsec_tncfg_get_info: device '%s' has no private data space!\n", + dev->name); + } + len += ipsec_snprintf(buffer+len, length-len, "\n"); + + if (len >= max_content) { + /* we've done all that can fit -- stop loop */ + len = max_content; /* truncate crap */ + break; + } else { + const off_t pos = begin + len; + if (pos <= offset) { + len = 0; + begin = pos; + } + } + } + } + *start = buffer + (offset - begin); /* Start of wanted data */ + len -= (offset - begin); /* Start slop */ + if (len > length) + len = length; + return len; +} + +IPSEC_PROCFS_DEBUG_NO_STATIC +int +ipsec_version_get_info(char *buffer, + char **start, + off_t offset, + int length IPSEC_PROC_LAST_ARG) +{ + int len = 0; + off_t begin = 0; + + KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS, + "klips_debug:ipsec_version_get_info: " + "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n", + buffer, + *start, + (int)offset, + length); + + len += ipsec_snprintf(buffer+len, length-len, "strongSwan version: %s\n", + ipsec_version_code()); +#if 0 + KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS, + "klips_debug:ipsec_version_get_info: " + "ipsec_init version: %s\n", + ipsec_init_c_version); + KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS, + "klips_debug:ipsec_version_get_info: " + "ipsec_tunnel version: %s\n", + ipsec_tunnel_c_version); + KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS, + "klips_debug:ipsec_version_get_info: " + "ipsec_netlink version: %s\n", + ipsec_netlink_c_version); + KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS, + "klips_debug:ipsec_version_get_info: " + "radij_c_version: %s\n", + radij_c_version); +#endif + + *start = buffer + (offset - begin); /* Start of wanted data */ + len -= (offset - begin); /* Start slop */ + if (len > length) + len = length; + return len; +} + +IPSEC_PROCFS_DEBUG_NO_STATIC +int +ipsec_birth_info(char *page, + char **start, + off_t offset, + int count, + int *eof, + void *data) +{ + struct ipsec_birth_reply *ibr = (struct ipsec_birth_reply *)data; + int len; + + if(offset >= ibr->packet_template_len) { + if(eof) { + *eof=1; + } + return 0; + } + + len = ibr->packet_template_len; + len -= offset; + if (len > count) + len = count; + + memcpy(page + offset, ibr->packet_template+offset, len); + + return len; +} + +IPSEC_PROCFS_DEBUG_NO_STATIC +int +ipsec_birth_set(struct file *file, const char *buffer, + unsigned long count, void *data) +{ + struct ipsec_birth_reply *ibr = (struct ipsec_birth_reply *)data; + int len; + + MOD_INC_USE_COUNT; + if(count > IPSEC_BIRTH_TEMPLATE_MAXLEN) { + len = IPSEC_BIRTH_TEMPLATE_MAXLEN; + } else { + len = count; + } + + if(copy_from_user(ibr->packet_template, buffer, len)) { + MOD_DEC_USE_COUNT; + return -EFAULT; + } + ibr->packet_template_len = len; + + MOD_DEC_USE_COUNT; + + return len; +} + + +#ifdef CONFIG_IPSEC_DEBUG +IPSEC_PROCFS_DEBUG_NO_STATIC +int +ipsec_klipsdebug_get_info(char *buffer, + char **start, + off_t offset, + int length IPSEC_PROC_LAST_ARG) +{ + int len = 0; + off_t begin = 0; + + KLIPS_PRINT(debug_tunnel & DB_TN_PROCFS, + "klips_debug:ipsec_klipsdebug_get_info: " + "buffer=0p%p, *start=0p%p, offset=%d, length=%d\n", + buffer, + *start, + (int)offset, + length); + + len += ipsec_snprintf(buffer+len, length-len, "debug_tunnel=%08x.\n", debug_tunnel); + len += ipsec_snprintf(buffer+len, length-len, "debug_xform=%08x.\n", debug_xform); + len += ipsec_snprintf(buffer+len, length-len, "debug_eroute=%08x.\n", debug_eroute); + len += ipsec_snprintf(buffer+len, length-len, "debug_spi=%08x.\n", debug_spi); + len += ipsec_snprintf(buffer+len, length-len, "debug_radij=%08x.\n", debug_radij); + len += ipsec_snprintf(buffer+len, length-len, "debug_esp=%08x.\n", debug_esp); + len += ipsec_snprintf(buffer+len, length-len, "debug_ah=%08x.\n", debug_ah); + len += ipsec_snprintf(buffer+len, length-len, "debug_rcv=%08x.\n", debug_rcv); + len += ipsec_snprintf(buffer+len, length-len, "debug_pfkey=%08x.\n", debug_pfkey); + + *start = buffer + (offset - begin); /* Start of wanted data */ + len -= (offset - begin); /* Start slop */ + if (len > length) + len = length; + return len; +} +#endif /* CONFIG_IPSEC_DEBUG */ + +IPSEC_PROCFS_DEBUG_NO_STATIC +int +ipsec_stats_get_int_info(char *buffer, + char **start, + off_t offset, + int length, + int *eof, + void *data) +{ + /* Limit of useful snprintf output */ + const int max_content = length > 0? length-1 : 0; + + int len = 0; + int *thing; + + thing = (int *)data; + + len = ipsec_snprintf(buffer+len, length-len, "%08x\n", *thing); + + if (len >= max_content) + len = max_content; /* truncate crap */ + + *start = buffer + offset; /* Start of wanted data */ + return len > offset? len - offset : 0; +} + +#ifndef PROC_FS_2325 +struct proc_dir_entry ipsec_eroute = +{ + 0, + 12, "ipsec_eroute", + S_IFREG | S_IRUGO, 1, 0, 0, 0, + &proc_net_inode_operations, + ipsec_eroute_get_info, + NULL, NULL, NULL, NULL, NULL +}; + +struct proc_dir_entry ipsec_spi = +{ + 0, + 9, "ipsec_spi", + S_IFREG | S_IRUGO, 1, 0, 0, 0, + &proc_net_inode_operations, + ipsec_spi_get_info, + NULL, NULL, NULL, NULL, NULL +}; + +struct proc_dir_entry ipsec_spigrp = +{ + 0, + 12, "ipsec_spigrp", + S_IFREG | S_IRUGO, 1, 0, 0, 0, + &proc_net_inode_operations, + ipsec_spigrp_get_info, + NULL, NULL, NULL, NULL, NULL +}; + +struct proc_dir_entry ipsec_tncfg = +{ + 0, + 11, "ipsec_tncfg", + S_IFREG | S_IRUGO, 1, 0, 0, 0, + &proc_net_inode_operations, + ipsec_tncfg_get_info, + NULL, NULL, NULL, NULL, NULL +}; + +struct proc_dir_entry ipsec_version = +{ + 0, + 13, "ipsec_version", + S_IFREG | S_IRUGO, 1, 0, 0, 0, + &proc_net_inode_operations, + ipsec_version_get_info, + NULL, NULL, NULL, NULL, NULL +}; + +#ifdef CONFIG_IPSEC_DEBUG +struct proc_dir_entry ipsec_klipsdebug = +{ + 0, + 16, "ipsec_klipsdebug", + S_IFREG | S_IRUGO, 1, 0, 0, 0, + &proc_net_inode_operations, + ipsec_klipsdebug_get_info, + NULL, NULL, NULL, NULL, NULL +}; +#endif /* CONFIG_IPSEC_DEBUG */ +#endif /* !PROC_FS_2325 */ +#endif /* CONFIG_PROC_FS */ + +#if defined(PROC_FS_2325) +struct ipsec_proc_list { + char *name; + struct proc_dir_entry **parent; + struct proc_dir_entry **dir; + read_proc_t *readthing; + write_proc_t *writething; + void *data; +}; +static struct ipsec_proc_list proc_items[]={ +#ifdef CONFIG_IPSEC_DEBUG + {"klipsdebug", &proc_net_ipsec_dir, NULL, ipsec_klipsdebug_get_info, NULL, NULL}, +#endif + {"eroute", &proc_net_ipsec_dir, &proc_eroute_dir, NULL, NULL, NULL}, + {"all", &proc_eroute_dir, NULL, ipsec_eroute_get_info, NULL, NULL}, + {"spi", &proc_net_ipsec_dir, &proc_spi_dir, NULL, NULL, NULL}, + {"all", &proc_spi_dir, NULL, ipsec_spi_get_info, NULL, NULL}, + {"spigrp", &proc_net_ipsec_dir, &proc_spigrp_dir, NULL, NULL, NULL}, + {"all", &proc_spigrp_dir, NULL, ipsec_spigrp_get_info, NULL, NULL}, + {"birth", &proc_net_ipsec_dir, &proc_birth_dir, NULL, NULL, NULL}, + {"ipv4", &proc_birth_dir, NULL, ipsec_birth_info, ipsec_birth_set, (void *)&ipsec_ipv4_birth_packet}, + {"ipv6", &proc_birth_dir, NULL, ipsec_birth_info, ipsec_birth_set, (void *)&ipsec_ipv6_birth_packet}, + {"xforms", &proc_net_ipsec_dir, NULL, ipsec_xform_get_info, NULL, NULL}, + {"tncfg", &proc_net_ipsec_dir, NULL, ipsec_tncfg_get_info, NULL, NULL}, + {"stats", &proc_net_ipsec_dir, &proc_stats_dir, NULL, NULL, NULL}, + {"trap_count", &proc_stats_dir, NULL, ipsec_stats_get_int_info, NULL, &ipsec_xmit_trap_count}, + {"trap_sendcount", &proc_stats_dir, NULL, ipsec_stats_get_int_info, NULL, &ipsec_xmit_trap_sendcount}, + {"version", &proc_net_ipsec_dir, NULL, ipsec_version_get_info, NULL, NULL}, + {NULL, NULL, NULL, NULL, NULL, NULL} +}; +#endif + +int +ipsec_proc_init() +{ + int error = 0; +#ifdef IPSEC_PROC_SUBDIRS + struct proc_dir_entry *item; +#endif + + /* + * just complain because pluto won't run without /proc! + */ +#ifndef CONFIG_PROC_FS +#error You must have PROC_FS built in to use KLIPS +#endif + + /* for 2.0 kernels */ +#if !defined(PROC_FS_2325) && !defined(PROC_FS_21) + error |= proc_register_dynamic(&proc_net, &ipsec_eroute); + error |= proc_register_dynamic(&proc_net, &ipsec_spi); + error |= proc_register_dynamic(&proc_net, &ipsec_spigrp); + error |= proc_register_dynamic(&proc_net, &ipsec_tncfg); + error |= proc_register_dynamic(&proc_net, &ipsec_version); +#ifdef CONFIG_IPSEC_DEBUG + error |= proc_register_dynamic(&proc_net, &ipsec_klipsdebug); +#endif /* CONFIG_IPSEC_DEBUG */ +#endif + + /* for 2.2 kernels */ +#if !defined(PROC_FS_2325) && defined(PROC_FS_21) + error |= proc_register(proc_net, &ipsec_eroute); + error |= proc_register(proc_net, &ipsec_spi); + error |= proc_register(proc_net, &ipsec_spigrp); + error |= proc_register(proc_net, &ipsec_tncfg); + error |= proc_register(proc_net, &ipsec_version); +#ifdef CONFIG_IPSEC_DEBUG + error |= proc_register(proc_net, &ipsec_klipsdebug); +#endif /* CONFIG_IPSEC_DEBUG */ +#endif + + /* for 2.4 kernels */ +#if defined(PROC_FS_2325) + /* create /proc/net/ipsec */ + + /* zero these out before we initialize /proc/net/ipsec/birth/stuff */ + memset(&ipsec_ipv4_birth_packet, 0, sizeof(struct ipsec_birth_reply)); + memset(&ipsec_ipv6_birth_packet, 0, sizeof(struct ipsec_birth_reply)); + + proc_net_ipsec_dir = proc_mkdir("ipsec", proc_net); + if(proc_net_ipsec_dir == NULL) { + /* no point in continuing */ + return 1; + } + + { + struct ipsec_proc_list *it; + + it=proc_items; + while(it->name!=NULL) { + if(it->dir) { + /* make a dir instead */ + item = proc_mkdir(it->name, *it->parent); + *it->dir = item; + } else { + item = create_proc_entry(it->name, 0400, *it->parent); + } + if(item) { + item->read_proc = it->readthing; + item->write_proc = it->writething; + item->data = it->data; +#ifdef MODULE + item->owner = THIS_MODULE; +#endif + } else { + error |= 1; + } + it++; + } + } + + /* now create some symlinks to provide compatibility */ + proc_symlink("ipsec_eroute", proc_net, "ipsec/eroute/all"); + proc_symlink("ipsec_spi", proc_net, "ipsec/spi/all"); + proc_symlink("ipsec_spigrp", proc_net, "ipsec/spigrp/all"); + proc_symlink("ipsec_tncfg", proc_net, "ipsec/tncfg"); + proc_symlink("ipsec_version",proc_net, "ipsec/version"); + proc_symlink("ipsec_klipsdebug",proc_net,"ipsec/klipsdebug"); + +#endif /* !PROC_FS_2325 */ + + return error; +} + +void +ipsec_proc_cleanup() +{ + + /* for 2.0 and 2.2 kernels */ +#if !defined(PROC_FS_2325) + +#ifdef CONFIG_IPSEC_DEBUG + if (proc_net_unregister(ipsec_klipsdebug.low_ino) != 0) + printk("klips_debug:ipsec_cleanup: " + "cannot unregister /proc/net/ipsec_klipsdebug\n"); +#endif /* CONFIG_IPSEC_DEBUG */ + + if (proc_net_unregister(ipsec_version.low_ino) != 0) + printk("klips_debug:ipsec_cleanup: " + "cannot unregister /proc/net/ipsec_version\n"); + if (proc_net_unregister(ipsec_eroute.low_ino) != 0) + printk("klips_debug:ipsec_cleanup: " + "cannot unregister /proc/net/ipsec_eroute\n"); + if (proc_net_unregister(ipsec_spi.low_ino) != 0) + printk("klips_debug:ipsec_cleanup: " + "cannot unregister /proc/net/ipsec_spi\n"); + if (proc_net_unregister(ipsec_spigrp.low_ino) != 0) + printk("klips_debug:ipsec_cleanup: " + "cannot unregister /proc/net/ipsec_spigrp\n"); + if (proc_net_unregister(ipsec_tncfg.low_ino) != 0) + printk("klips_debug:ipsec_cleanup: " + "cannot unregister /proc/net/ipsec_tncfg\n"); +#endif + + /* for 2.4 kernels */ +#if defined(PROC_FS_2325) + { + struct ipsec_proc_list *it; + + /* find end of list */ + it=proc_items; + while(it->name!=NULL) { + it++; + } + it--; + + do { + remove_proc_entry(it->name, *it->parent); + it--; + } while(it > proc_items); + } + + +#ifdef CONFIG_IPSEC_DEBUG + remove_proc_entry("ipsec_klipsdebug", proc_net); +#endif /* CONFIG_IPSEC_DEBUG */ + remove_proc_entry("ipsec_eroute", proc_net); + remove_proc_entry("ipsec_spi", proc_net); + remove_proc_entry("ipsec_spigrp", proc_net); + remove_proc_entry("ipsec_tncfg", proc_net); + remove_proc_entry("ipsec_version", proc_net); + remove_proc_entry("ipsec", proc_net); +#endif /* 2.4 kernel */ +} + + |