1004 lines
28 KiB
C
1004 lines
28 KiB
C
/*
|
|
* @(#) /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 */
|
|
}
|
|
|
|
|