/* * @(#) /proc file system interface code. * * Copyright (C) 1996, 1997 John Ioannidis. * Copyright (C) 1998, 1999, 2000, 2001 Richard Guy Briggs * 2001 Michael Richardson * * 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 . * * 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 #include #define __NO_VERSION__ #include #include /* printk() */ #include "freeswan/ipsec_param.h" #ifdef MALLOC_SLAB # include /* kmalloc() */ #else /* MALLOC_SLAB */ # include /* kmalloc() */ #endif /* MALLOC_SLAB */ #include /* error codes */ #include /* size_t */ #include /* mark_bh */ #include /* struct device, and other headers */ #include /* eth_type_trans */ #include /* struct iphdr */ #include /* struct sockaddr_in */ #include #include #ifdef SPINLOCK #ifdef SPINLOCK_23 #include /* *lock* */ #else /* SPINLOCK_23 */ #include /* *lock* */ #endif /* SPINLOCK_23 */ #endif /* SPINLOCK */ #ifdef NET_21 #include #include #endif /* NET_21 */ #include #include #ifdef CONFIG_PROC_FS #include #endif /* CONFIG_PROC_FS */ #ifdef NETLINK_SOCK #include #else #include #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 #include #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 */ }