Commit 3f4f4e5c authored by Doug Ledford's avatar Doug Ledford

Merge aladin.rdu.redhat.com:/usr/local/home/dledford/bk/linus-2.5

into aladin.rdu.redhat.com:/usr/src/2.5
parents e05290c8 2c0889e4
......@@ -66,7 +66,9 @@ OLDESP = 0x34
OLDSS = 0x38
CF_MASK = 0x00000001
TF_MASK = 0x00000100
IF_MASK = 0x00000200
DF_MASK = 0x00000400
NT_MASK = 0x00004000
VM_MASK = 0x00020000
......@@ -134,6 +136,17 @@ ENTRY(lcall7)
movl %eax,EFLAGS(%esp) #
movl %edx,EIP(%esp) # Now we move them to their "normal" places
movl %ecx,CS(%esp) #
#
# Call gates don't clear TF and NT in eflags like
# traps do, so we need to do it ourselves.
# %eax already contains eflags (but it may have
# DF set, clear that also)
#
andl $~(DF_MASK | TF_MASK | NT_MASK),%eax
pushl %eax
popfl
movl %esp, %ebx
pushl %ebx
andl $-8192, %ebx # GET_THREAD_INFO
......@@ -156,6 +169,17 @@ ENTRY(lcall27)
movl %eax,EFLAGS(%esp) #
movl %edx,EIP(%esp) # Now we move them to their "normal" places
movl %ecx,CS(%esp) #
#
# Call gates don't clear TF and NT in eflags like
# traps do, so we need to do it ourselves.
# %eax already contains eflags (but it may have
# DF set, clear that also)
#
andl $~(DF_MASK | TF_MASK | NT_MASK),%eax
pushl %eax
popfl
movl %esp, %ebx
pushl %ebx
andl $-8192, %ebx # GET_THREAD_INFO
......
......@@ -90,7 +90,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
me->name, strtab + sym->st_name);
return -ENOENT;
}
v += rel->r_addend;
v += rel[i].r_addend;
switch (ELF32_R_TYPE(rel[i].r_info)) {
case R_SPARC_32:
......@@ -126,7 +126,7 @@ int apply_relocate_add(Elf32_Shdr *sechdrs,
me->name,
(int) (ELF32_R_TYPE(rel[i].r_info) & 0xff));
return -ENOEXEC;
}
};
}
return 0;
}
......
......@@ -10,6 +10,113 @@
#include <linux/vmalloc.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/mm.h>
static struct vm_struct * modvmlist = NULL;
static void module_unmap(void * addr)
{
struct vm_struct **p, *tmp;
int i;
if (!addr)
return;
if ((PAGE_SIZE-1) & (unsigned long) addr) {
printk("Trying to unmap module with bad address (%p)\n", addr);
return;
}
for (p = &modvmlist ; (tmp = *p) ; p = &tmp->next) {
if (tmp->addr == addr) {
*p = tmp->next;
goto found;
}
}
printk("Trying to unmap nonexistent module vm area (%p)\n", addr);
return;
found:
unmap_vm_area(tmp);
for (i = 0; i < tmp->nr_pages; i++) {
if (unlikely(!tmp->pages[i]))
BUG();
__free_page(tmp->pages[i]);
}
kfree(tmp->pages);
kfree(tmp);
}
static void *module_map(unsigned long size)
{
struct vm_struct **p, *tmp, *area;
struct page **pages;
void * addr;
unsigned int nr_pages, array_size, i;
size = PAGE_ALIGN(size);
if (!size || size > MODULES_LEN)
return NULL;
addr = (void *) MODULES_VADDR;
for (p = &modvmlist; (tmp = *p) ; p = &tmp->next) {
if (size + (unsigned long) addr < (unsigned long) tmp->addr)
break;
addr = (void *) (tmp->size + (unsigned long) tmp->addr);
}
if ((unsigned long) addr + size >= MODULES_END)
return NULL;
area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
if (!area)
return NULL;
area->size = size + PAGE_SIZE;
area->addr = addr;
area->next = *p;
area->pages = NULL;
area->nr_pages = 0;
area->phys_addr = 0;
*p = area;
nr_pages = size >> PAGE_SHIFT;
array_size = (nr_pages * sizeof(struct page *));
area->nr_pages = nr_pages;
area->pages = pages = kmalloc(array_size, GFP_KERNEL);
if (!area->pages)
goto fail;
memset(area->pages, 0, array_size);
for (i = 0; i < area->nr_pages; i++) {
area->pages[i] = alloc_page(GFP_KERNEL);
if (unlikely(!area->pages[i]))
goto fail;
}
if (map_vm_area(area, PAGE_KERNEL, &pages)) {
unmap_vm_area(area);
goto fail;
}
return area->addr;
fail:
if (area->pages) {
for (i = 0; i < area->nr_pages; i++) {
if (area->pages[i])
__free_page(area->pages[i]);
}
kfree(area->pages);
}
kfree(area);
return NULL;
}
static void *alloc_and_zero(unsigned long size)
{
......@@ -19,7 +126,7 @@ static void *alloc_and_zero(unsigned long size)
if (size == 0)
return NULL;
ret = vmalloc(size);
ret = module_map(size);
if (!ret)
ret = ERR_PTR(-ENOMEM);
else
......@@ -31,7 +138,7 @@ static void *alloc_and_zero(unsigned long size)
/* Free memory returned from module_core_alloc/module_init_alloc */
void module_free(struct module *mod, void *module_region)
{
vfree(module_region);
module_unmap(module_region);
/* FIXME: If module_region == mod->init_region, trim exception
table entries. */
}
......@@ -82,6 +189,9 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
location = (u8 *)sechdrs[sechdrs[relsec].sh_info].sh_offset
+ rel[i].r_offset;
loc32 = (u32 *) location;
BUG_ON(((u64)location >> (u64)32) != (u64)0);
/* This is the symbol it is referring to */
sym = (Elf64_Sym *)sechdrs[symindex].sh_offset
+ ELF64_R_SYM(rel[i].r_info);
......@@ -90,7 +200,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
me->name, strtab + sym->st_name);
return -ENOENT;
}
v += rel->r_addend;
v += rel[i].r_addend;
switch (ELF64_R_TYPE(rel[i].r_info) & 0xff) {
case R_SPARC_64:
......@@ -137,7 +247,7 @@ int apply_relocate_add(Elf64_Shdr *sechdrs,
me->name,
(int) (ELF64_R_TYPE(rel[i].r_info) & 0xff));
return -ENOEXEC;
}
};
}
return 0;
}
......
......@@ -3113,24 +3113,18 @@ asmlinkage int sparc32_execve(struct pt_regs *regs)
#ifdef CONFIG_MODULES
extern asmlinkage long sys_init_module(const char *name_user,
struct module *mod_user);
extern asmlinkage long sys_init_module(void *, unsigned long, const char *);
/* Hey, when you're trying to init module, take time and prepare us a nice
* 64bit module structure, even if from 32bit modutils... Why to pollute
* kernel... :))
*/
asmlinkage int sys32_init_module(const char *name_user,
struct module *mod_user)
asmlinkage int sys32_init_module(void *umod, u32 len, const char *uargs)
{
return sys_init_module(name_user, mod_user);
return sys_init_module(umod, len, uargs);
}
extern asmlinkage long sys_delete_module(const char *name_user);
extern asmlinkage long sys_delete_module(const char *, unsigned int);
asmlinkage int sys32_delete_module(const char *name_user)
asmlinkage int sys32_delete_module(const char *name_user, unsigned int flags)
{
return sys_delete_module(name_user);
return sys_delete_module(name_user, flags);
}
#else /* CONFIG_MODULES */
......
......@@ -263,8 +263,7 @@ static int c_show(struct seq_file *m, void *p)
struct crypto_alg *alg = (struct crypto_alg *)p;
seq_printf(m, "name : %s\n", alg->cra_name);
seq_printf(m, "module : %s\n", alg->cra_module ?
alg->cra_module->name : "[static]");
seq_printf(m, "module : %s\n", module_name(alg->cra_module));
seq_printf(m, "blocksize : %u\n", alg->cra_blocksize);
switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) {
......
......@@ -70,6 +70,7 @@ struct in_addr {
#define IP_MTU 14
#define IP_FREEBIND 15
#define IP_IPSEC_POLICY 16
#define IP_XFRM_POLICY 17
/* BSD compatibility */
#define IP_RECVRETOPTS IP_RETOPTS
......
......@@ -242,6 +242,13 @@ static inline void module_put(struct module *module)
#endif /* CONFIG_MODULE_UNLOAD */
/* This is a #define so the string doesn't get put in every .o file */
#define module_name(mod) \
({ \
struct module *__mod = (mod); \
__mod ? __mod->name : "kernel"; \
})
#define __unsafe(mod) \
do { \
if (mod && !(mod)->unsafe) { \
......@@ -265,6 +272,8 @@ do { \
#define try_module_get(module) 1
#define module_put(module) do { } while(0)
#define module_name(mod) "kernel"
#define __unsafe(mod)
#endif /* CONFIG_MODULES */
......
......@@ -57,7 +57,4 @@ struct udp_sock {
#define udp_sk(__sk) (&((struct udp_sock *)__sk)->udp)
extern int udp_proc_init(void);
extern void udp_proc_exit(void);
#endif /* _LINUX_UDP_H */
......@@ -91,6 +91,22 @@ struct xfrm_stats {
__u32 integrity_failed;
};
enum
{
XFRM_POLICY_IN = 0,
XFRM_POLICY_OUT = 1,
XFRM_POLICY_FWD = 2,
XFRM_POLICY_MAX = 3
};
enum
{
XFRM_SHARE_ANY, /* No limitations */
XFRM_SHARE_SESSION, /* For this session only */
XFRM_SHARE_USER, /* For this user only */
XFRM_SHARE_UNIQUE /* Use once */
};
/* Netlink configuration messages. */
#define XFRM_MSG_BASE 0x10
......@@ -104,8 +120,9 @@ struct xfrm_stats {
#define XFRM_MSG_ALLOCSPI (RTM_BASE + 6)
#define XFRM_MSG_ACQUIRE (RTM_BASE + 7)
#define XFRM_MSG_EXPIRE (RTM_BASE + 8)
#define XFRM_MSG_MAX (XFRM_MSG_ACQUIRE+1)
#define XFRM_MSG_MAX (XFRM_MSG_EXPIRE+1)
struct xfrm_user_tmpl {
struct xfrm_id id;
......@@ -113,6 +130,7 @@ struct xfrm_user_tmpl {
__u16 reqid;
__u8 mode;
__u8 share;
__u8 optional;
__u32 aalgos;
__u32 ealgos;
__u32 calgos;
......@@ -135,9 +153,9 @@ struct xfrm_usersa_info {
struct xfrm_lifetime_cfg lft;
struct xfrm_lifetime_cur curlft;
struct xfrm_stats stats;
__u32 seq;
__u16 family;
__u16 reqid;
__u8 sa_type;
__u8 mode; /* 0=transport,1=tunnel */
__u8 replay_window;
};
......@@ -148,15 +166,26 @@ struct xfrm_usersa_id {
__u8 proto;
};
struct xfrm_userspi_info {
struct xfrm_usersa_info info;
u32 min;
u32 max;
};
struct xfrm_userpolicy_info {
struct xfrm_selector sel;
struct xfrm_id id;
struct xfrm_lifetime_cfg lft;
struct xfrm_lifetime_cur curlft;
__u32 priority;
__u32 index;
__u16 family;
__u8 dir;
__u8 action;
#define XFRM_POLICY_ALLOW 0
#define XFRM_POLICY_BLOCK 1
__u8 flags;
#define XFRM_POLICY_LOCALOK 1 /* Allow user to override global policy */
__u8 share;
};
struct xfrm_userpolicy_id {
......@@ -165,4 +194,22 @@ struct xfrm_userpolicy_id {
__u8 dir;
};
struct xfrm_user_acquire {
struct xfrm_id id;
xfrm_address_t saddr;
struct xfrm_userpolicy_info policy;
__u32 aalgos;
__u32 ealgos;
__u32 calgos;
__u32 seq;
};
struct xfrm_user_expire {
struct xfrm_usersa_info state;
__u8 hard;
};
#define XFRMGRP_ACQUIRE 1
#define XFRMGRP_EXPIRE 2
#endif /* _LINUX_XFRM_H */
......@@ -276,7 +276,4 @@ static inline void fib_res_put(struct fib_result *res)
#endif
}
extern int fib_proc_init(void);
extern void fib_proc_exit(void);
#endif /* _NET_FIB_H */
......@@ -76,6 +76,4 @@ extern struct udp_mib udp_statistics[NR_CPUS*2];
#define UDP_INC_STATS_BH(field) SNMP_INC_STATS_BH(udp_statistics, field)
#define UDP_INC_STATS_USER(field) SNMP_INC_STATS_USER(udp_statistics, field)
extern int udp_proc_init(void);
#endif /* _UDP_H */
......@@ -96,6 +96,7 @@ struct xfrm_state
u8 replay_window;
u8 aalgo, ealgo, calgo;
u16 reqid;
u16 family;
xfrm_address_t saddr;
int header_len;
int trailer_len;
......@@ -187,22 +188,6 @@ struct xfrm_tmpl
#define XFRM_MAX_DEPTH 3
enum
{
XFRM_SHARE_ANY, /* No limitations */
XFRM_SHARE_SESSION, /* For this session only */
XFRM_SHARE_USER, /* For this user only */
XFRM_SHARE_UNIQUE /* Use once */
};
enum
{
XFRM_POLICY_IN = 0,
XFRM_POLICY_OUT = 1,
XFRM_POLICY_FWD = 2,
XFRM_POLICY_MAX = 3
};
struct xfrm_policy
{
struct xfrm_policy *next;
......@@ -217,11 +202,9 @@ struct xfrm_policy
struct xfrm_lifetime_cfg lft;
struct xfrm_lifetime_cur curlft;
struct dst_entry *bundles;
__u16 family;
__u8 action;
#define XFRM_POLICY_ALLOW 0
#define XFRM_POLICY_BLOCK 1
__u8 flags;
#define XFRM_POLICY_LOCALOK 1 /* Allow user to override global policy */
__u8 dead;
__u8 xfrm_nr;
struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH];
......@@ -390,7 +373,7 @@ struct xfrm_policy *xfrm_policy_delete(int dir, struct xfrm_selector *sel);
struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete);
void xfrm_policy_flush(void);
void xfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi);
struct xfrm_state * xfrm_find_acq(u8 mode, u16 reqid, u8 proto, u32 daddr, u32 saddr);
struct xfrm_state * xfrm_find_acq(u8 mode, u16 reqid, u8 proto, u32 daddr, u32 saddr, int create);
extern void xfrm_policy_flush(void);
extern void xfrm_policy_kill(struct xfrm_policy *);
extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol);
......
......@@ -211,12 +211,7 @@ get_exec_domain_list(char *page)
for (ep = exec_domains; ep && len < PAGE_SIZE - 80; ep = ep->next)
len += sprintf(page + len, "%d-%d\t%-16s\t[%s]\n",
ep->pers_low, ep->pers_high, ep->name,
#ifdef CONFIG_MODULES
ep->module ? ep->module->name : "kernel"
#else
"kernel"
#endif
);
module_name(ep->module));
read_unlock(&exec_domains_lock);
return (len);
}
......
......@@ -541,10 +541,10 @@ static int rif_get_info(char *buffer,char **start, off_t offset, int length)
static int __init rif_init(void)
{
init_timer(&rif_timer);
rif_timer.expires = RIF_TIMEOUT;
rif_timer.data = 0L;
rif_timer.function = rif_check_expire;
init_timer(&rif_timer);
add_timer(&rif_timer);
proc_net_create("tr_rif",0,rif_get_info);
......
......@@ -104,7 +104,7 @@ extern void mpc_proc_clean(void);
struct mpoa_client *mpcs = NULL; /* FIXME */
static struct atm_mpoa_qos *qos_head = NULL;
static struct timer_list mpc_timer;
static struct timer_list mpc_timer = TIMER_INITIALIZER(NULL, 0, 0);
static struct mpoa_client *find_mpc_by_itfnum(int itf)
......
......@@ -1151,8 +1151,8 @@ void neigh_table_init(struct neigh_table *tbl)
tasklet_init(&tbl->gc_task, SMP_TIMER_NAME(neigh_periodic_timer),
(unsigned long)tbl);
#endif
init_timer(&tbl->gc_timer);
tbl->lock = RW_LOCK_UNLOCKED;
init_timer(&tbl->gc_timer);
tbl->gc_timer.data = (unsigned long)tbl;
tbl->gc_timer.function = neigh_periodic_timer;
tbl->gc_timer.expires = now + tbl->gc_interval +
......
......@@ -362,5 +362,13 @@ config INET_ESP
If unsure, say Y.
config XFRM_USER
tristate "IP: IPsec user configuration interface"
---help---
Support for IPsec user configuration interface used
by native Linux tools.
If unsure, say Y.
source "net/ipv4/netfilter/Kconfig"
......@@ -20,6 +20,7 @@ obj-$(CONFIG_INET_AH) += ah.o
obj-$(CONFIG_INET_ESP) += esp.o
obj-$(CONFIG_IP_PNP) += ipconfig.o
obj-$(CONFIG_NETFILTER) += netfilter/
obj-$(CONFIG_XFRM_USER) += xfrm_user.o
obj-y += xfrm_policy.o xfrm_state.o xfrm_input.o
......
......@@ -1160,16 +1160,20 @@ module_init(inet_init);
/* ------------------------------------------------------------------------ */
#ifdef CONFIG_PROC_FS
extern int fib_proc_init(void);
extern void fib_proc_exit(void);
extern int ip_misc_proc_init(void);
extern int raw_get_info(char *, char **, off_t, int);
extern int tcp_get_info(char *, char **, off_t, int);
extern int raw_proc_init(void);
extern void raw_proc_exit(void);
extern int tcp_get_info(char *buffer, char **start, off_t offset, int length);
extern int udp_proc_init(void);
extern void udp_proc_exit(void);
int __init ipv4_proc_init(void)
{
int rc = 0;
if (!proc_net_create("raw", 0, raw_get_info))
if (raw_proc_init())
goto out_raw;
if (!proc_net_create("tcp", 0, tcp_get_info))
goto out_tcp;
......@@ -1188,7 +1192,7 @@ int __init ipv4_proc_init(void)
out_udp:
proc_net_remove("tcp");
out_tcp:
proc_net_remove("raw");
raw_proc_exit();
out_raw:
rc = -ENOMEM;
goto out;
......
......@@ -189,7 +189,7 @@ int ah_output(struct sk_buff *skb)
top_iph->saddr = x->props.saddr.xfrm4_addr;
top_iph->daddr = x->id.daddr.xfrm4_addr;
ah = (struct ip_auth_hdr*)(top_iph+1);
ah->nexthdr = IPPROTO_IP;
ah->nexthdr = IPPROTO_IPIP;
} else {
memcpy(&tmp_iph, skb->data, iph->ihl*4);
top_iph = (struct iphdr*)skb_push(skb, x->props.header_len);
......
......@@ -190,11 +190,10 @@ esp_hmac_digest(struct esp_data *esp, struct sk_buff *skb, int offset,
struct crypto_tfm *tfm = esp->auth.tfm;
char *digest = esp->auth.work_digest;
memset(auth_data, 0, esp->auth.authlen);
crypto_hmac_init(tfm, esp->auth.key, &esp->auth.key_len);
skb_digest_walk(skb, tfm, offset, len);
crypto_hmac_final(tfm, esp->auth.key, &esp->auth.key_len, digest);
memcpy(auth_data, digest, crypto_tfm_alg_digestsize(tfm));
memcpy(auth_data, digest, esp->auth.authlen);
}
/* Check that skb data bits are writable. If they are not, copy data
......@@ -370,7 +369,7 @@ int esp_output(struct sk_buff *skb)
if (x->props.mode) {
top_iph = (struct iphdr*)skb_push(skb, x->props.header_len);
esph = (struct ip_esp_hdr*)(top_iph+1);
*(u8*)(trailer->tail - 1) = IPPROTO_IP;
*(u8*)(trailer->tail - 1) = IPPROTO_IPIP;
top_iph->ihl = 5;
top_iph->version = 4;
top_iph->tos = iph->tos; /* DS disclosed */
......@@ -463,16 +462,16 @@ int esp_input(struct xfrm_state *x, struct sk_buff *skb)
/* If integrity check is required, do this. */
if (esp->auth.authlen) {
int icvsize = crypto_tfm_alg_digestsize(esp->auth.tfm);
u8 sum[icvsize];
u8 sum1[icvsize];
u8 sum[esp->auth.authlen];
u8 sum1[esp->auth.authlen];
esp->auth.digest(esp, skb, 0, skb->len-esp->auth.authlen, sum);
if (skb_copy_bits(skb, skb->len-esp->auth.authlen, sum1, icvsize))
if (skb_copy_bits(skb, skb->len-esp->auth.authlen, sum1,
esp->auth.authlen))
BUG();
if (unlikely(memcmp(sum, sum1, icvsize))) {
if (unlikely(memcmp(sum, sum1, esp->auth.authlen))) {
x->stats.integrity_failed++;
goto out;
}
......@@ -605,14 +604,20 @@ int esp_init_state(struct xfrm_state *x, void *args)
memset(esp, 0, sizeof(*esp));
if (x->aalg) {
int digestsize;
esp->auth.key = x->aalg->alg_key;
esp->auth.key_len = (x->aalg->alg_key_len+7)/8;
esp->auth.tfm = crypto_alloc_tfm(x->aalg->alg_name, 0);
if (esp->auth.tfm == NULL)
goto error;
esp->auth.digest = esp_hmac_digest;
esp->auth.authlen = crypto_tfm_alg_digestsize(esp->auth.tfm);
esp->auth.work_digest = kmalloc(esp->auth.authlen, GFP_KERNEL);
digestsize = crypto_tfm_alg_digestsize(esp->auth.tfm);
/* XXX RFC2403 and RFC 2404 truncate auth to 96 bit */
esp->auth.authlen = 12;
if (esp->auth.authlen > digestsize) /* XXX */
BUG();
esp->auth.work_digest = kmalloc(digestsize, GFP_KERNEL);
if (!esp->auth.work_digest)
goto error;
}
......
......@@ -1092,16 +1092,4 @@ void __init fib_proc_exit(void)
{
remove_proc_entry("route", proc_net);
}
#else /* CONFIG_PROC_FS */
int __init fib_proc_init(void)
{
return 0;
}
void __init fib_proc_exit(void)
{
return 0;
}
#endif /* CONFIG_PROC_FS */
......@@ -626,6 +626,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt
break;
case IP_IPSEC_POLICY:
case IP_XFRM_POLICY:
err = xfrm_user_policy(sk, optname, optval, optlen);
break;
......
......@@ -361,8 +361,6 @@ helper_cmp(const struct ip_nat_helper *helper,
return ip_ct_tuple_mask_cmp(tuple, &helper->tuple, &helper->mask);
}
#define MODULE_MAX_NAMELEN 32
int ip_nat_helper_register(struct ip_nat_helper *me)
{
int ret = 0;
......@@ -374,14 +372,13 @@ int ip_nat_helper_register(struct ip_nat_helper *me)
&& ct_helper->me) {
__MOD_INC_USE_COUNT(ct_helper->me);
} else {
#ifdef CONFIG_MODULES
/* We are a NAT helper for protocol X. If we need
* respective conntrack helper for protoccol X, compute
* conntrack helper name and try to load module */
char name[MODULE_MAX_NAMELEN];
const char *tmp = me->me->name;
char name[MODULE_NAME_LEN];
const char *tmp = module_name(me->me);
if (strlen(tmp) + 6 > MODULE_MAX_NAMELEN) {
if (strlen(tmp) + 6 > MODULE_NAME_LEN) {
printk("%s: unable to "
"compute conntrack helper name "
"from %s\n", __FUNCTION__, tmp);
......@@ -403,7 +400,6 @@ int ip_nat_helper_register(struct ip_nat_helper *me)
"because kernel was compiled without kernel "
"module loader support\n", name);
return -EBUSY;
#endif
#endif
}
}
......
......@@ -26,27 +26,18 @@
* Andi Kleen : Add support for open_requests and
* split functions for more readibility.
* Andi Kleen : Add support for /proc/net/netstat
* Arnaldo C. Melo : Convert to seq_file
*
* 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.
*/
#include <asm/system.h>
#include <linux/sched.h>
#include <linux/socket.h>
#include <linux/net.h>
#include <linux/un.h>
#include <linux/in.h>
#include <linux/param.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <net/ip.h>
#include <linux/types.h>
#include <net/icmp.h>
#include <net/protocol.h>
#include <net/tcp.h>
#include <net/udp.h>
#include <linux/skbuff.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <net/sock.h>
......@@ -57,7 +48,7 @@ static int fold_prot_inuse(struct proto *proto)
int res = 0;
int cpu;
for (cpu=0; cpu<NR_CPUS; cpu++)
for (cpu = 0; cpu < NR_CPUS; cpu++)
res += proto->stats[cpu].inuse;
return res;
......@@ -66,38 +57,35 @@ static int fold_prot_inuse(struct proto *proto)
/*
* Report socket allocation statistics [mea@utu.fi]
*/
int afinet_get_info(char *buffer, char **start, off_t offset, int length)
static int sockstat_seq_show(struct seq_file *seq, void *v)
{
/* From net/socket.c */
extern int socket_get_info(char *, char **, off_t, int);
extern void socket_seq_show(struct seq_file *seq);
int len = socket_get_info(buffer,start,offset,length);
len += sprintf(buffer+len,"TCP: inuse %d orphan %d tw %d alloc %d mem %d\n",
fold_prot_inuse(&tcp_prot),
atomic_read(&tcp_orphan_count), tcp_tw_count,
atomic_read(&tcp_sockets_allocated),
socket_seq_show(seq);
seq_printf(seq, "TCP: inuse %d orphan %d tw %d alloc %d mem %d\n",
fold_prot_inuse(&tcp_prot), atomic_read(&tcp_orphan_count),
tcp_tw_count, atomic_read(&tcp_sockets_allocated),
atomic_read(&tcp_memory_allocated));
len += sprintf(buffer+len,"UDP: inuse %d\n",
fold_prot_inuse(&udp_prot));
len += sprintf(buffer+len,"RAW: inuse %d\n",
fold_prot_inuse(&raw_prot));
len += sprintf(buffer+len, "FRAG: inuse %d memory %d\n",
ip_frag_nqueues, atomic_read(&ip_frag_mem));
if (offset >= len)
{
*start = buffer;
seq_printf(seq, "UDP: inuse %d\n", fold_prot_inuse(&udp_prot));
seq_printf(seq, "RAW: inuse %d\n", fold_prot_inuse(&raw_prot));
seq_printf(seq, "FRAG: inuse %d memory %d\n", ip_frag_nqueues,
atomic_read(&ip_frag_mem));
return 0;
}
*start = buffer + offset;
len -= offset;
if (len > length)
len = length;
if (len < 0)
len = 0;
return len;
}
static int sockstat_seq_open(struct inode *inode, struct file *file)
{
return single_open(file, sockstat_seq_show, NULL);
}
static struct file_operations sockstat_seq_fops = {
.open = sockstat_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
static unsigned long fold_field(unsigned long *begin, int sz, int nr)
{
unsigned long res = 0;
......@@ -105,9 +93,9 @@ static unsigned long fold_field(unsigned long *begin, int sz, int nr)
sz /= sizeof(unsigned long);
for (i=0; i<NR_CPUS; i++) {
res += begin[2*i*sz + nr];
res += begin[(2*i+1)*sz + nr];
for (i = 0; i < NR_CPUS; i++) {
res += begin[2 * i * sz + nr];
res += begin[(2 * i + 1) * sz + nr];
}
return res;
}
......@@ -115,52 +103,73 @@ static unsigned long fold_field(unsigned long *begin, int sz, int nr)
/*
* Called from the PROCfs module. This outputs /proc/net/snmp.
*/
int snmp_get_info(char *buffer, char **start, off_t offset, int length)
static int snmp_seq_show(struct seq_file *seq, void *v)
{
extern int sysctl_ip_default_ttl;
int len, i;
len = sprintf (buffer,
"Ip: Forwarding DefaultTTL InReceives InHdrErrors InAddrErrors ForwDatagrams InUnknownProtos InDiscards InDelivers OutRequests OutDiscards OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs ReasmFails FragOKs FragFails FragCreates\n"
"Ip: %d %d", ipv4_devconf.forwarding ? 1 : 2, sysctl_ip_default_ttl);
for (i=0; i<offsetof(struct ip_mib, __pad)/sizeof(unsigned long); i++)
len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)ip_statistics, sizeof(struct ip_mib), i));
len += sprintf (buffer + len,
"\nIcmp: InMsgs InErrors InDestUnreachs InTimeExcds InParmProbs InSrcQuenchs InRedirects InEchos InEchoReps InTimestamps InTimestampReps InAddrMasks InAddrMaskReps OutMsgs OutErrors OutDestUnreachs OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects OutEchos OutEchoReps OutTimestamps OutTimestampReps OutAddrMasks OutAddrMaskReps\n"
"Icmp:");
for (i=0; i<offsetof(struct icmp_mib, dummy)/sizeof(unsigned long); i++)
len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)icmp_statistics, sizeof(struct icmp_mib), i));
len += sprintf (buffer + len,
"\nTcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens PassiveOpens AttemptFails EstabResets CurrEstab InSegs OutSegs RetransSegs InErrs OutRsts\n"
"Tcp:");
for (i=0; i<offsetof(struct tcp_mib, __pad)/sizeof(unsigned long); i++)
len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)tcp_statistics, sizeof(struct tcp_mib), i));
len += sprintf (buffer + len,
"\nUdp: InDatagrams NoPorts InErrors OutDatagrams\n"
int i;
seq_printf(seq, "Ip: Forwarding DefaultTTL InReceives InHdrErrors "
"InAddrErrors ForwDatagrams InUnknownProtos "
"InDiscards InDelivers OutRequests OutDiscards "
"OutNoRoutes ReasmTimeout ReasmReqds ReasmOKs "
"ReasmFails FragOKs FragFails FragCreates\nIp: %d %d",
ipv4_devconf.forwarding ? 1 : 2, sysctl_ip_default_ttl);
for (i = 0;
i < offsetof(struct ip_mib, __pad) / sizeof(unsigned long); i++)
seq_printf(seq, " %lu",
fold_field((unsigned long *)ip_statistics,
sizeof(struct ip_mib), i));
seq_printf(seq, "\nIcmp: InMsgs InErrors InDestUnreachs InTimeExcds "
"InParmProbs InSrcQuenchs InRedirects InEchos "
"InEchoReps InTimestamps InTimestampReps InAddrMasks "
"InAddrMaskReps OutMsgs OutErrors OutDestUnreachs "
"OutTimeExcds OutParmProbs OutSrcQuenchs OutRedirects "
"OutEchos OutEchoReps OutTimestamps OutTimestampReps "
"OutAddrMasks OutAddrMaskReps\nIcmp:");
for (i = 0;
i < offsetof(struct icmp_mib, dummy) / sizeof(unsigned long); i++)
seq_printf(seq, " %lu",
fold_field((unsigned long *)icmp_statistics,
sizeof(struct icmp_mib), i));
seq_printf(seq, "\nTcp: RtoAlgorithm RtoMin RtoMax MaxConn ActiveOpens "
"PassiveOpens AttemptFails EstabResets CurrEstab "
"InSegs OutSegs RetransSegs InErrs OutRsts\nTcp:");
for (i = 0;
i < offsetof(struct tcp_mib, __pad) / sizeof(unsigned long); i++)
seq_printf(seq, " %lu",
fold_field((unsigned long *)tcp_statistics,
sizeof(struct tcp_mib), i));
seq_printf(seq, "\nUdp: InDatagrams NoPorts InErrors OutDatagrams\n"
"Udp:");
for (i=0; i<offsetof(struct udp_mib, __pad)/sizeof(unsigned long); i++)
len += sprintf(buffer+len, " %lu", fold_field((unsigned long*)udp_statistics, sizeof(struct udp_mib), i));
len += sprintf (buffer + len, "\n");
for (i = 0;
i < offsetof(struct udp_mib, __pad) / sizeof(unsigned long); i++)
seq_printf(seq, " %lu",
fold_field((unsigned long *)udp_statistics,
sizeof(struct udp_mib), i));
if (offset >= len)
{
*start = buffer;
seq_putc(seq, '\n');
return 0;
}
*start = buffer + offset;
len -= offset;
if (len > length)
len = length;
if (len < 0)
len = 0;
return len;
}
static int snmp_seq_open(struct inode *inode, struct file *file)
{
return single_open(file, snmp_seq_show, NULL);
}
static struct file_operations snmp_seq_fops = {
.open = snmp_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/*
* Output /proc/net/netstat
*/
......@@ -181,7 +190,8 @@ static int netstat_seq_show(struct seq_file *seq, void *v)
" TCPPureAcks TCPHPAcks"
" TCPRenoRecovery TCPSackRecovery"
" TCPSACKReneging"
" TCPFACKReorder TCPSACKReorder TCPRenoReorder TCPTSReorder"
" TCPFACKReorder TCPSACKReorder TCPRenoReorder"
" TCPTSReorder"
" TCPFullUndo TCPPartialUndo TCPDSACKUndo TCPLossUndo"
" TCPLoss TCPLostRetransmit"
" TCPRenoFailures TCPSackFailures TCPLossFailures"
......@@ -189,14 +199,14 @@ static int netstat_seq_show(struct seq_file *seq, void *v)
" TCPTimeouts"
" TCPRenoRecoveryFail TCPSackRecoveryFail"
" TCPSchedulerFailed TCPRcvCollapsed"
" TCPDSACKOldSent TCPDSACKOfoSent TCPDSACKRecv TCPDSACKOfoRecv"
" TCPDSACKOldSent TCPDSACKOfoSent TCPDSACKRecv"
" TCPDSACKOfoRecv"
" TCPAbortOnSyn TCPAbortOnData TCPAbortOnClose"
" TCPAbortOnMemory TCPAbortOnTimeout TCPAbortOnLinger"
" TCPAbortFailed TCPMemoryPressures\n"
"TcpExt:");
for (i = 0;
i < offsetof(struct linux_mib, __pad) / sizeof(unsigned long);
i++)
i < offsetof(struct linux_mib, __pad) / sizeof(unsigned long); i++)
seq_printf(seq, " %lu",
fold_field((unsigned long *)net_statistics,
sizeof(struct linux_mib), i));
......@@ -219,20 +229,26 @@ static struct file_operations netstat_seq_fops = {
int __init ip_misc_proc_init(void)
{
int rc = 0;
struct proc_dir_entry *p = create_proc_entry("netstat", S_IRUGO, proc_net);
struct proc_dir_entry *p;
p = create_proc_entry("netstat", S_IRUGO, proc_net);
if (!p)
goto out_netstat;
p->proc_fops = &netstat_seq_fops;
if (!proc_net_create("snmp", 0, snmp_get_info))
p = create_proc_entry("snmp", S_IRUGO, proc_net);
if (!p)
goto out_snmp;
if (!proc_net_create("sockstat", 0, afinet_get_info))
p->proc_fops = &snmp_seq_fops;
p = create_proc_entry("sockstat", S_IRUGO, proc_net);
if (!p)
goto out_sockstat;
p->proc_fops = &sockstat_seq_fops;
out:
return rc;
out_sockstat:
proc_net_remove("snmp");
remove_proc_entry("snmp", proc_net);
out_snmp:
remove_proc_entry("netstat", proc_net);
out_netstat:
......
......@@ -40,31 +40,42 @@
*/
#include <linux/config.h>
#include <asm/system.h>
#include <asm/atomic.h>
#include <asm/byteorder.h>
#include <asm/current.h>
#include <asm/uaccess.h>
#include <asm/ioctls.h>
#include <linux/types.h>
#include <linux/sched.h>
#include <linux/stddef.h>
#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/timer.h>
#include <linux/mm.h>
#include <linux/aio.h>
#include <linux/kernel.h>
#include <linux/fcntl.h>
#include <linux/spinlock.h>
#include <linux/sockios.h>
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/mroute.h>
#include <net/tcp.h>
#include <net/protocol.h>
#include <linux/in_route.h>
#include <linux/route.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>
#include <net/dst.h>
#include <net/sock.h>
#include <linux/gfp.h>
#include <linux/ip.h>
#include <net/ip.h>
#include <net/icmp.h>
#include <net/udp.h>
#include <net/raw.h>
#include <net/snmp.h>
#include <net/inet_common.h>
#include <net/checksum.h>
#include <net/xfrm.h>
#include <linux/rtnetlink.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
struct sock *raw_v4_htable[RAWV4_HTABLE_SIZE];
......@@ -656,7 +667,95 @@ static int raw_ioctl(struct sock *sk, int cmd, unsigned long arg)
}
}
static void get_raw_sock(struct sock *sp, char *tmpbuf, int i)
struct proto raw_prot = {
.name = "RAW",
.close = raw_close,
.connect = udp_connect,
.disconnect = udp_disconnect,
.ioctl = raw_ioctl,
.init = raw_init,
.setsockopt = raw_setsockopt,
.getsockopt = raw_getsockopt,
.sendmsg = raw_sendmsg,
.recvmsg = raw_recvmsg,
.bind = raw_bind,
.backlog_rcv = raw_rcv_skb,
.hash = raw_v4_hash,
.unhash = raw_v4_unhash,
};
#ifdef CONFIG_PROC_FS
struct raw_iter_state {
int bucket;
};
#define raw_seq_private(seq) ((struct raw_iter_state *)&seq->private)
static struct sock *raw_get_first(struct seq_file *seq)
{
struct sock *sk = NULL;
struct raw_iter_state* state = raw_seq_private(seq);
for (state->bucket = 0; state->bucket < RAWV4_HTABLE_SIZE; ++state->bucket) {
sk = raw_v4_htable[state->bucket];
while (sk && sk->family != PF_INET)
sk = sk->next;
if (sk)
break;
}
return sk;
}
static struct sock *raw_get_next(struct seq_file *seq, struct sock *sk)
{
struct raw_iter_state* state = raw_seq_private(seq);
do {
sk = sk->next;
try_again:
} while (sk && sk->family != PF_INET);
if (!sk && ++state->bucket < RAWV4_HTABLE_SIZE) {
sk = raw_v4_htable[state->bucket];
goto try_again;
}
return sk;
}
static struct sock *raw_get_idx(struct seq_file *seq, loff_t pos)
{
struct sock *sk = raw_get_first(seq);
if (sk)
while (pos && (sk = raw_get_next(seq, sk)) != NULL)
--pos;
return pos ? NULL : sk;
}
static void *raw_seq_start(struct seq_file *seq, loff_t *pos)
{
read_lock(&raw_v4_lock);
return *pos ? raw_get_idx(seq, *pos) : (void *)1;
}
static void *raw_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{
struct sock *sk;
if (v == (void *)1)
sk = raw_get_first(seq);
else
sk = raw_get_next(seq, v);
++*pos;
return sk;
}
static void raw_seq_stop(struct seq_file *seq, void *v)
{
read_unlock(&raw_v4_lock);
}
static __inline__ char *get_raw_sock(struct sock *sp, char *tmpbuf, int i)
{
struct inet_opt *inet = inet_sk(sp);
unsigned int dest = inet->daddr,
......@@ -668,65 +767,63 @@ static void get_raw_sock(struct sock *sp, char *tmpbuf, int i)
" %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p",
i, src, srcp, dest, destp, sp->state,
atomic_read(&sp->wmem_alloc), atomic_read(&sp->rmem_alloc),
0, 0L, 0,
sock_i_uid(sp), 0,
sock_i_ino(sp),
0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp),
atomic_read(&sp->refcnt), sp);
return tmpbuf;
}
int raw_get_info(char *buffer, char **start, off_t offset, int length)
static int raw_seq_show(struct seq_file *seq, void *v)
{
int len = 0, num = 0, i;
off_t pos = 128;
off_t begin;
char tmpbuf[129];
if (offset < 128)
len += sprintf(buffer, "%-127s\n",
if (v == (void *)1)
seq_printf(seq, "%-127s\n",
" sl local_address rem_address st tx_queue "
"rx_queue tr tm->when retrnsmt uid timeout "
"inode");
read_lock(&raw_v4_lock);
for (i = 0; i < RAWV4_HTABLE_SIZE; i++) {
struct sock *sk;
else {
struct raw_iter_state *state = raw_seq_private(seq);
for (sk = raw_v4_htable[i]; sk; sk = sk->next, num++) {
if (sk->family != PF_INET)
continue;
pos += 128;
if (pos <= offset)
continue;
get_raw_sock(sk, tmpbuf, i);
len += sprintf(buffer + len, "%-127s\n", tmpbuf);
if (len >= length)
goto out;
}
seq_printf(seq, "%-127s\n",
get_raw_sock(v, tmpbuf, state->bucket));
}
out:
read_unlock(&raw_v4_lock);
begin = len - (pos - offset);
*start = buffer + begin;
len -= begin;
if (len > length)
len = length;
if (len < 0)
len = 0;
return len;
return 0;
}
struct proto raw_prot = {
.name = "RAW",
.close = raw_close,
.connect = udp_connect,
.disconnect = udp_disconnect,
.ioctl = raw_ioctl,
.init = raw_init,
.setsockopt = raw_setsockopt,
.getsockopt = raw_getsockopt,
.sendmsg = raw_sendmsg,
.recvmsg = raw_recvmsg,
.bind = raw_bind,
.backlog_rcv = raw_rcv_skb,
.hash = raw_v4_hash,
.unhash = raw_v4_unhash,
static struct seq_operations raw_seq_ops = {
.start = raw_seq_start,
.next = raw_seq_next,
.stop = raw_seq_stop,
.show = raw_seq_show,
};
static int raw_seq_open(struct inode *inode, struct file *file)
{
return seq_open(file, &raw_seq_ops);
}
static struct file_operations raw_seq_fops = {
.open = raw_seq_open,
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
};
int __init raw_proc_init(void)
{
struct proc_dir_entry *p;
int rc = 0;
p = create_proc_entry("raw", S_IRUGO, proc_net);
if (p)
p->proc_fops = &raw_seq_fops;
else
rc = -ENOMEM;
return rc;
}
void __init raw_proc_exit(void)
{
remove_proc_entry("raw", proc_net);
}
#endif /* CONFIG_PROC_FS */
......@@ -944,7 +944,7 @@ static int udp_queue_rcv_skb(struct sock * sk, struct sk_buff *skb)
/*
* Charge it to the socket, dropping if the queue is full.
*/
if (!xfrm_policy_check(NULL, XFRM_POLICY_IN, skb)) {
if (!xfrm_policy_check(sk, XFRM_POLICY_IN, skb)) {
kfree_skb(skb);
return -1;
}
......@@ -1377,16 +1377,4 @@ void __init udp_proc_exit(void)
{
remove_proc_entry("udp", proc_net);
}
#else /* CONFIG_PROC_FS */
int __init udp_proc_init(void)
{
return 0;
}
void __init udp_proc_exit(void)
{
return 0;
}
#endif /* CONFIG_PROC_FS */
......@@ -91,7 +91,7 @@ int xfrm4_rcv(struct sk_buff *skb)
iph = skb->nh.iph;
if (x->props.mode) {
if (iph->protocol != IPPROTO_IP)
if (iph->protocol != IPPROTO_IPIP)
goto drop;
skb->nh.raw = skb->data;
iph = skb->nh.iph;
......
......@@ -386,7 +386,7 @@ xfrm_state_lookup(u32 daddr, u32 spi, u8 proto)
}
struct xfrm_state *
xfrm_find_acq(u8 mode, u16 reqid, u8 proto, u32 daddr, u32 saddr)
xfrm_find_acq(u8 mode, u16 reqid, u8 proto, u32 daddr, u32 saddr, int create)
{
struct xfrm_state *x, *x0;
unsigned h = ntohl(daddr);
......@@ -400,10 +400,11 @@ xfrm_find_acq(u8 mode, u16 reqid, u8 proto, u32 daddr, u32 saddr)
mode == x->props.mode &&
proto == x->id.proto &&
saddr == x->props.saddr.xfrm4_addr &&
reqid == x->props.reqid) {
reqid == x->props.reqid &&
x->km.state == XFRM_STATE_ACQ) {
if (!x0)
x0 = x;
if (x->km.state != XFRM_STATE_ACQ)
if (x->id.spi)
continue;
x0 = x;
break;
......@@ -411,7 +412,7 @@ xfrm_find_acq(u8 mode, u16 reqid, u8 proto, u32 daddr, u32 saddr)
}
if (x0) {
atomic_inc(&x0->refcnt);
} else if ((x0 = xfrm_state_alloc()) != NULL) {
} else if (create && (x0 = xfrm_state_alloc()) != NULL) {
x0->sel.daddr.xfrm4_addr = daddr;
x0->sel.daddr.xfrm4_mask = ~0;
x0->sel.saddr.xfrm4_addr = saddr;
......
/* xfrm_user.c: User interface to configure xfrm engine.
*
* Copyright (C) 2002 David S. Miller (davem@redhat.com)
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/socket.h>
#include <linux/string.h>
#include <linux/net.h>
#include <linux/skbuff.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
#include <linux/pfkeyv2.h>
#include <linux/ipsec.h>
#include <linux/init.h>
#include <net/sock.h>
#include <net/xfrm.h>
static struct sock *xfrm_nl;
static int verify_one_alg(struct rtattr **xfrma, enum xfrm_attr_type_t type)
{
struct rtattr *rt = xfrma[type];
struct xfrm_algo *algp;
if (!rt)
return 0;
if ((rt->rta_len - sizeof(*rt)) < sizeof(*algp))
return -EINVAL;
algp = RTA_DATA(rt);
switch (type) {
case XFRMA_ALG_AUTH:
case XFRMA_ALG_CRYPT:
if (!algp->alg_key_len)
return -EINVAL;
break;
case XFRMA_ALG_COMP:
/* Zero length keys are legal. */
break;
default:
return -EINVAL;
};
algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0';
return 0;
}
static int verify_newsa_info(struct xfrm_usersa_info *p,
struct rtattr **xfrma)
{
int err;
err = -EINVAL;
switch (p->family) {
case AF_INET:
break;
case AF_INET6: /* XXX */
err = -EAFNOSUPPORT;
/* fallthru */
default:
goto out;
};
err = -EINVAL;
switch (p->id.proto) {
case IPPROTO_AH:
if (!xfrma[XFRMA_ALG_AUTH] ||
xfrma[XFRMA_ALG_CRYPT] ||
xfrma[XFRMA_ALG_COMP])
goto out;
break;
case IPPROTO_ESP:
if ((!xfrma[XFRMA_ALG_AUTH] &&
!xfrma[XFRMA_ALG_CRYPT]) ||
xfrma[XFRMA_ALG_COMP])
goto out;
break;
case IPPROTO_COMP:
if (!xfrma[XFRMA_ALG_COMP] ||
xfrma[XFRMA_ALG_AUTH] ||
xfrma[XFRMA_ALG_CRYPT])
goto out;
break;
default:
goto out;
};
if ((err = verify_one_alg(xfrma, XFRMA_ALG_AUTH)))
goto out;
if ((err = verify_one_alg(xfrma, XFRMA_ALG_CRYPT)))
goto out;
if ((err = verify_one_alg(xfrma, XFRMA_ALG_COMP)))
goto out;
err = -EINVAL;
switch (p->mode) {
case 0:
case 1:
break;
default:
goto out;
};
err = 0;
out:
return err;
}
static int attach_one_algo(struct xfrm_algo **algpp, struct rtattr *u_arg)
{
struct rtattr *rta = u_arg;
struct xfrm_algo *p, *ualg;
if (!rta)
return 0;
ualg = RTA_DATA(rta);
p = kmalloc(sizeof(*ualg) + ualg->alg_key_len, GFP_KERNEL);
if (!p)
return -ENOMEM;
memcpy(p, ualg, sizeof(*ualg) + ualg->alg_key_len);
*algpp = p;
return 0;
}
static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
{
memcpy(&x->id, &p->id, sizeof(x->id));
memcpy(&x->sel, &p->sel, sizeof(x->sel));
memcpy(&x->lft, &p->lft, sizeof(x->lft));
x->props.mode = p->mode;
x->props.replay_window = p->replay_window;
x->props.reqid = p->reqid;
x->props.family = p->family;
x->props.saddr = x->sel.saddr;
}
static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p,
struct rtattr **xfrma,
int *errp)
{
struct xfrm_state *x = xfrm_state_alloc();
int err = -ENOMEM;
if (!x)
goto error_no_put;
copy_from_user_state(x, p);
if ((err = attach_one_algo(&x->aalg, xfrma[XFRMA_ALG_AUTH])))
goto error;
if ((err = attach_one_algo(&x->ealg, xfrma[XFRMA_ALG_CRYPT])))
goto error;
if ((err = attach_one_algo(&x->calg, xfrma[XFRMA_ALG_COMP])))
goto error;
err = -ENOENT;
x->type = xfrm_get_type(x->id.proto);
if (x->type == NULL)
goto error;
err = x->type->init_state(x, NULL);
if (err)
goto error;
x->curlft.add_time = (unsigned long) xtime.tv_sec;
x->km.state = XFRM_STATE_VALID;
x->km.seq = p->seq;
return x;
error:
xfrm_state_put(x);
error_no_put:
*errp = err;
return NULL;
}
static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
struct xfrm_usersa_info *p = NLMSG_DATA(nlh);
struct xfrm_state *x, *x1;
int err;
err = verify_newsa_info(p, (struct rtattr **) xfrma);
if (err)
return err;
x = xfrm_state_construct(p, (struct rtattr **) xfrma, &err);
if (!x)
return err;
x1 = xfrm_state_lookup(x->props.saddr.xfrm4_addr,
x->id.spi, x->id.proto);
if (x1) {
xfrm_state_put(x);
xfrm_state_put(x1);
return -EEXIST;
}
xfrm_state_insert(x);
return 0;
}
static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
struct xfrm_state *x;
struct xfrm_usersa_id *p = NLMSG_DATA(nlh);
x = xfrm_state_lookup(p->saddr.xfrm4_addr, p->spi, p->proto);
if (x == NULL)
return -ESRCH;
xfrm_state_delete(x);
xfrm_state_put(x);
return 0;
}
static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p)
{
memcpy(&p->id, &x->id, sizeof(p->id));
memcpy(&p->sel, &x->sel, sizeof(p->sel));
memcpy(&p->lft, &x->lft, sizeof(p->lft));
memcpy(&p->curlft, &x->curlft, sizeof(p->curlft));
memcpy(&p->stats, &x->stats, sizeof(p->stats));
p->mode = x->props.mode;
p->replay_window = x->props.replay_window;
p->reqid = x->props.reqid;
p->family = x->props.family;
p->seq = x->km.seq;
}
struct xfrm_dump_info {
struct sk_buff *in_skb;
struct sk_buff *out_skb;
u32 nlmsg_seq;
int start_idx;
int this_idx;
};
static int dump_one_state(struct xfrm_state *x, int count, void *ptr)
{
struct xfrm_dump_info *sp = ptr;
struct sk_buff *in_skb = sp->in_skb;
struct sk_buff *skb = sp->out_skb;
struct xfrm_usersa_info *p;
struct nlmsghdr *nlh;
unsigned char *b = skb->tail;
if (sp->this_idx < sp->start_idx)
goto out;
nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid,
sp->nlmsg_seq,
XFRM_MSG_NEWSA, sizeof(*p));
nlh->nlmsg_flags = 0;
p = NLMSG_DATA(nlh);
copy_to_user_state(x, p);
if (x->aalg)
RTA_PUT(skb, XFRMA_ALG_AUTH, sizeof(*(x->aalg)), x->aalg);
if (x->ealg)
RTA_PUT(skb, XFRMA_ALG_CRYPT, sizeof(*(x->ealg)), x->ealg);
if (x->calg)
RTA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg);
nlh->nlmsg_len = skb->tail - b;
out:
sp->this_idx++;
return 0;
nlmsg_failure:
rtattr_failure:
skb_trim(skb, b - skb->data);
return -1;
}
static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb)
{
struct xfrm_dump_info info;
info.in_skb = cb->skb;
info.out_skb = skb;
info.nlmsg_seq = cb->nlh->nlmsg_seq;
info.this_idx = 0;
info.start_idx = cb->args[0];
(void) xfrm_state_walk(IPSEC_PROTO_ANY, dump_one_state, &info);
cb->args[0] = info.this_idx;
return skb->len;
}
static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb,
struct xfrm_state *x, u32 seq)
{
struct xfrm_dump_info info;
struct sk_buff *skb;
skb = alloc_skb(NLMSG_GOODSIZE, GFP_ATOMIC);
if (!skb)
return ERR_PTR(-ENOMEM);
NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
info.in_skb = in_skb;
info.out_skb = skb;
info.nlmsg_seq = seq;
info.this_idx = info.start_idx = 0;
if (dump_one_state(x, 0, &info)) {
kfree_skb(skb);
return NULL;
}
return skb;
}
static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
struct xfrm_usersa_id *p = NLMSG_DATA(nlh);
struct xfrm_state *x;
struct sk_buff *resp_skb;
int err;
x = xfrm_state_lookup(p->saddr.xfrm4_addr, p->spi, p->proto);
err = -ESRCH;
if (x == NULL)
goto out_noput;
resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq);
if (IS_ERR(resp_skb)) {
err = PTR_ERR(resp_skb);
} else {
err = netlink_unicast(xfrm_nl, resp_skb,
NETLINK_CB(skb).pid, MSG_DONTWAIT);
}
xfrm_state_put(x);
out_noput:
return err;
}
static int verify_userspi_info(struct xfrm_userspi_info *p)
{
switch (p->info.id.proto) {
case IPPROTO_AH:
case IPPROTO_ESP:
break;
case IPPROTO_COMP:
/* IPCOMP spi is 16-bits. */
if (p->min >= 0x10000 ||
p->max >= 0x10000)
return -EINVAL;
default:
return -EINVAL;
};
if (p->min > p->max)
return -EINVAL;
return 0;
}
static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
struct xfrm_state *x;
struct xfrm_userspi_info *p;
struct sk_buff *resp_skb;
int err;
p = NLMSG_DATA(nlh);
err = verify_userspi_info(p);
if (err)
goto out_noput;
x = xfrm_find_acq(p->info.mode, p->info.reqid, p->info.id.proto,
p->info.sel.daddr.xfrm4_addr,
p->info.sel.saddr.xfrm4_addr, 1);
err = -ENOENT;
if (x == NULL)
goto out_noput;
resp_skb = ERR_PTR(-ENOENT);
spin_lock_bh(&x->lock);
if (x->km.state != XFRM_STATE_DEAD) {
xfrm_alloc_spi(x, p->min, p->max);
if (x->id.spi)
resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq);
}
spin_unlock_bh(&x->lock);
if (IS_ERR(resp_skb)) {
err = PTR_ERR(resp_skb);
goto out;
}
err = netlink_unicast(xfrm_nl, resp_skb,
NETLINK_CB(skb).pid, MSG_DONTWAIT);
out:
xfrm_state_put(x);
out_noput:
return err;
}
static int verify_policy_dir(__u8 dir)
{
switch (dir) {
case XFRM_POLICY_IN:
case XFRM_POLICY_OUT:
case XFRM_POLICY_FWD:
break;
default:
return -EINVAL;
};
return 0;
}
static int verify_newpolicy_info(struct xfrm_userpolicy_info *p)
{
switch (p->share) {
case XFRM_SHARE_ANY:
case XFRM_SHARE_SESSION:
case XFRM_SHARE_USER:
case XFRM_SHARE_UNIQUE:
break;
default:
return -EINVAL;
};
switch (p->action) {
case XFRM_POLICY_ALLOW:
case XFRM_POLICY_BLOCK:
break;
default:
return -EINVAL;
};
return verify_policy_dir(p->dir);
}
static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut,
int nr)
{
int i;
xp->xfrm_nr = nr;
for (i = 0; i < nr; i++, ut++) {
struct xfrm_tmpl *t = &xp->xfrm_vec[i];
memcpy(&t->id, &ut->id, sizeof(struct xfrm_id));
memcpy(&t->saddr, &ut->saddr,
sizeof(xfrm_address_t));
t->reqid = ut->reqid;
t->mode = ut->mode;
t->share = ut->share;
t->optional = ut->optional;
t->aalgos = ut->aalgos;
t->ealgos = ut->ealgos;
t->calgos = ut->calgos;
}
}
static int copy_user_tmpl(struct xfrm_policy *pol, struct rtattr **xfrma)
{
struct rtattr *rt = xfrma[XFRMA_TMPL];
struct xfrm_user_tmpl *utmpl;
int nr;
if (!rt) {
pol->xfrm_nr = 0;
} else {
nr = (rt->rta_len - sizeof(*rt)) / sizeof(*utmpl);
if (nr > XFRM_MAX_DEPTH)
return -EINVAL;
copy_templates(pol, RTA_DATA(rt), nr);
}
return 0;
}
static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p)
{
xp->priority = p->priority;
xp->index = p->index;
memcpy(&xp->selector, &p->sel, sizeof(xp->selector));
memcpy(&xp->lft, &p->lft, sizeof(xp->lft));
xp->action = p->action;
xp->flags = p->flags;
xp->family = p->family;
/* XXX xp->share = p->share; */
}
static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p, int dir)
{
memcpy(&p->sel, &xp->selector, sizeof(p->sel));
memcpy(&p->lft, &xp->lft, sizeof(p->lft));
memcpy(&p->curlft, &xp->curlft, sizeof(p->curlft));
p->priority = xp->priority;
p->index = xp->index;
p->family = xp->family;
p->dir = dir;
p->action = xp->action;
p->flags = xp->flags;
p->share = XFRM_SHARE_ANY; /* XXX xp->share */
}
static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, struct rtattr **xfrma, int *errp)
{
struct xfrm_policy *xp = xfrm_policy_alloc(GFP_KERNEL);
int err;
if (!xp) {
*errp = -ENOMEM;
return NULL;
}
copy_from_user_policy(xp, p);
err = copy_user_tmpl(xp, xfrma);
if (err) {
*errp = err;
kfree(xp);
xp = NULL;
}
return xp;
}
static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
struct xfrm_userpolicy_info *p = NLMSG_DATA(nlh);
struct xfrm_policy *xp;
int err;
err = verify_newpolicy_info(p);
if (err)
return err;
xp = xfrm_policy_construct(p, (struct rtattr **) xfrma, &err);
if (!xp)
return err;
err = xfrm_policy_insert(p->dir, xp, 1);
if (err) {
kfree(xp);
return err;
}
xfrm_pol_put(xp);
return 0;
}
static int xfrm_del_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
struct xfrm_policy *xp;
struct xfrm_userpolicy_id *p;
int err;
p = NLMSG_DATA(nlh);
err = verify_policy_dir(p->dir);
if (err)
return err;
xp = xfrm_policy_delete(p->dir, &p->sel);
if (xp == NULL)
return -ENOENT;
xfrm_policy_kill(xp);
xfrm_pol_put(xp);
return 0;
}
static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr)
{
struct xfrm_dump_info *sp = ptr;
struct xfrm_userpolicy_info *p;
struct sk_buff *in_skb = sp->in_skb;
struct sk_buff *skb = sp->out_skb;
struct nlmsghdr *nlh;
unsigned char *b = skb->tail;
if (sp->this_idx < sp->start_idx)
goto out;
nlh = NLMSG_PUT(skb, NETLINK_CB(in_skb).pid,
sp->nlmsg_seq,
XFRM_MSG_NEWPOLICY, sizeof(*p));
p = NLMSG_DATA(nlh);
nlh->nlmsg_flags = 0;
copy_to_user_policy(xp, p, dir);
if (xp->xfrm_nr) {
struct xfrm_user_tmpl vec[XFRM_MAX_DEPTH];
int i;
for (i = 0; i < xp->xfrm_nr; i++) {
struct xfrm_user_tmpl *up = &vec[i];
struct xfrm_tmpl *kp = &xp->xfrm_vec[i];
memcpy(&up->id, &kp->id, sizeof(up->id));
memcpy(&up->saddr, &kp->saddr, sizeof(up->saddr));
up->reqid = kp->reqid;
up->mode = kp->mode;
up->share = kp->share;
up->optional = kp->optional;
up->aalgos = kp->aalgos;
up->ealgos = kp->ealgos;
up->calgos = kp->calgos;
}
RTA_PUT(skb, XFRMA_TMPL,
(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr),
vec);
}
nlh->nlmsg_len = skb->tail - b;
out:
sp->this_idx++;
return 0;
nlmsg_failure:
rtattr_failure:
skb_trim(skb, b - skb->data);
return -1;
}
static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb)
{
struct xfrm_dump_info info;
info.in_skb = cb->skb;
info.out_skb = skb;
info.nlmsg_seq = cb->nlh->nlmsg_seq;
info.start_idx = cb->args[0];
(void) xfrm_policy_walk(dump_one_policy, &info);
cb->args[0] = info.this_idx;
return skb->len;
}
static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb,
struct xfrm_policy *xp,
int dir, u32 seq)
{
struct xfrm_dump_info info;
struct sk_buff *skb;
skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
if (!skb)
return ERR_PTR(-ENOMEM);
NETLINK_CB(skb).dst_pid = NETLINK_CB(in_skb).pid;
info.in_skb = in_skb;
info.out_skb = skb;
info.nlmsg_seq = seq;
info.this_idx = info.start_idx = 0;
if (dump_one_policy(xp, dir, 0, &info) < 0) {
kfree_skb(skb);
return NULL;
}
return skb;
}
static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
{
struct xfrm_policy *xp;
struct xfrm_userpolicy_id *p;
struct sk_buff *resp_skb;
int err;
p = NLMSG_DATA(nlh);
xp = xfrm_policy_byid(p->dir, p->index, 0);
if (xp == NULL)
return -ENOENT;
resp_skb = xfrm_policy_netlink(skb, xp, p->dir, nlh->nlmsg_seq);
if (IS_ERR(resp_skb)) {
err = PTR_ERR(resp_skb);
} else {
err = netlink_unicast(xfrm_nl, resp_skb,
NETLINK_CB(skb).pid, MSG_DONTWAIT);
}
xfrm_pol_put(xp);
return err;
}
static const int xfrm_msg_min[(XFRM_MSG_MAX + 1 - XFRM_MSG_BASE)] = {
NLMSG_LENGTH(sizeof(struct xfrm_usersa_info)), /* NEW SA */
NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)), /* DEL SA */
NLMSG_LENGTH(sizeof(struct xfrm_usersa_id)), /* GET SA */
NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_info)),/* NEW POLICY */
NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id)), /* DEL POLICY */
NLMSG_LENGTH(sizeof(struct xfrm_userpolicy_id)), /* GET POLICY */
NLMSG_LENGTH(sizeof(struct xfrm_userspi_info)), /* ALLOC SPI */
NLMSG_LENGTH(sizeof(struct xfrm_user_acquire)), /* ACQUIRE */
NLMSG_LENGTH(sizeof(struct xfrm_user_expire)), /* EXPIRE */
};
static struct xfrm_link {
int (*doit)(struct sk_buff *, struct nlmsghdr *, void **);
int (*dump)(struct sk_buff *, struct netlink_callback *);
} xfrm_dispatch[] = {
{ .doit = xfrm_add_sa, },
{ .doit = xfrm_del_sa, },
{
.doit = xfrm_get_sa,
.dump = xfrm_dump_sa,
},
{ .doit = xfrm_add_policy },
{ .doit = xfrm_del_policy },
{
.doit = xfrm_get_policy,
.dump = xfrm_dump_policy,
},
{ .doit = xfrm_alloc_userspi },
};
static int xfrm_done(struct netlink_callback *cb)
{
return 0;
}
static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh, int *errp)
{
struct rtattr *xfrma[XFRMA_MAX];
struct xfrm_link *link;
int type, min_len, kind;
if (!(nlh->nlmsg_flags & NLM_F_REQUEST))
return 0;
type = nlh->nlmsg_type;
/* A control message: ignore them */
if (type < XFRM_MSG_BASE)
return 0;
/* Unknown message: reply with EINVAL */
if (type > XFRM_MSG_MAX)
goto err_einval;
type -= XFRM_MSG_BASE;
kind = (type & 3);
link = &xfrm_dispatch[type];
/* All operations require privileges, even GET */
if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN)) {
*errp = -EPERM;
return -1;
}
if (kind == 2 && (nlh->nlmsg_flags & NLM_F_DUMP)) {
u32 rlen;
if (link->dump == NULL)
goto err_einval;
if ((*errp = netlink_dump_start(xfrm_nl, skb, nlh,
link->dump,
xfrm_done)) != 0) {
return -1;
}
rlen = NLMSG_ALIGN(nlh->nlmsg_len);
if (rlen > skb->len)
rlen = skb->len;
skb_pull(skb, rlen);
return -1;
}
memset(xfrma, 0, sizeof(xfrma));
if (nlh->nlmsg_len < (min_len = xfrm_msg_min[type]))
goto err_einval;
if (nlh->nlmsg_len > min_len) {
int attrlen = nlh->nlmsg_len - NLMSG_ALIGN(min_len);
struct rtattr *attr = (void *) nlh + NLMSG_ALIGN(min_len);
while (RTA_OK(attr, attrlen)) {
unsigned short flavor = attr->rta_type;
if (flavor) {
if (flavor > XFRMA_MAX)
goto err_einval;
xfrma[flavor - 1] = attr;
}
attr = RTA_NEXT(attr, attrlen);
}
}
if (link->doit == NULL)
goto err_einval;
*errp = link->doit(skb, nlh, (void **) &xfrma);
return *errp;
err_einval:
*errp = -EINVAL;
return -1;
}
static int xfrm_user_rcv_skb(struct sk_buff *skb)
{
int err;
struct nlmsghdr *nlh;
while (skb->len >= NLMSG_SPACE(0)) {
u32 rlen;
nlh = (struct nlmsghdr *) skb->data;
if (nlh->nlmsg_len < sizeof(*nlh) ||
skb->len < nlh->nlmsg_len)
return 0;
rlen = NLMSG_ALIGN(nlh->nlmsg_len);
if (rlen > skb->len)
rlen = skb->len;
if (xfrm_user_rcv_msg(skb, nlh, &err)) {
if (err == 0)
return -1;
netlink_ack(skb, nlh, err);
} else if (nlh->nlmsg_flags & NLM_F_ACK)
netlink_ack(skb, nlh, 0);
skb_pull(skb, rlen);
}
return 0;
}
static void xfrm_netlink_rcv(struct sock *sk, int len)
{
do {
struct sk_buff *skb;
down(&xfrm_cfg_sem);
while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
if (xfrm_user_rcv_skb(skb)) {
if (skb->len)
skb_queue_head(&sk->receive_queue, skb);
else
kfree_skb(skb);
break;
}
kfree_skb(skb);
}
up(&xfrm_cfg_sem);
} while (xfrm_nl && xfrm_nl->receive_queue.qlen);
}
static int build_expire(struct sk_buff *skb, struct xfrm_state *x, int hard)
{
struct xfrm_user_expire *ue;
struct nlmsghdr *nlh;
unsigned char *b = skb->tail;
nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_EXPIRE,
sizeof(*ue));
ue = NLMSG_DATA(nlh);
nlh->nlmsg_flags = 0;
copy_to_user_state(x, &ue->state);
ue->hard = (hard != 0) ? 1 : 0;
nlh->nlmsg_len = skb->tail - b;
return skb->len;
nlmsg_failure:
skb_trim(skb, b - skb->data);
return -1;
}
static int xfrm_send_notify(struct xfrm_state *x, int hard)
{
struct sk_buff *skb;
skb = alloc_skb(sizeof(struct xfrm_user_expire) + 16, GFP_ATOMIC);
if (skb == NULL)
return -ENOMEM;
if (build_expire(skb, x, hard) < 0)
BUG();
NETLINK_CB(skb).dst_groups = XFRMGRP_EXPIRE;
netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_EXPIRE, GFP_ATOMIC);
return 0;
}
/* XXX Make this xfrm_state.c:xfrm_get_acqseq() */
static u32 get_acqseq(void)
{
u32 res;
static u32 acqseq;
static spinlock_t acqseq_lock = SPIN_LOCK_UNLOCKED;
spin_lock_bh(&acqseq_lock);
res = (++acqseq ? : ++acqseq);
spin_unlock_bh(&acqseq_lock);
return res;
}
static int build_acquire(struct sk_buff *skb, struct xfrm_state *x,
struct xfrm_tmpl *xt, struct xfrm_policy *xp,
int dir)
{
struct xfrm_user_acquire *ua;
struct nlmsghdr *nlh;
unsigned char *b = skb->tail;
__u32 seq = get_acqseq();
nlh = NLMSG_PUT(skb, 0, 0, XFRM_MSG_ACQUIRE,
sizeof(*ua));
ua = NLMSG_DATA(nlh);
nlh->nlmsg_flags = 0;
memcpy(&ua->id, &x->id, sizeof(ua->id));
memcpy(&ua->saddr, &x->props.saddr, sizeof(ua->saddr));
copy_to_user_policy(xp, &ua->policy, dir);
ua->aalgos = xt->aalgos;
ua->ealgos = xt->ealgos;
ua->calgos = xt->calgos;
ua->seq = x->km.seq = seq;
nlh->nlmsg_len = skb->tail - b;
return skb->len;
nlmsg_failure:
skb_trim(skb, b - skb->data);
return -1;
}
static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt,
struct xfrm_policy *xp, int dir)
{
struct sk_buff *skb;
skb = alloc_skb(sizeof(struct xfrm_user_acquire) + 16, GFP_ATOMIC);
if (skb == NULL)
return -ENOMEM;
if (build_acquire(skb, x, xt, xp, dir) < 0)
BUG();
NETLINK_CB(skb).dst_groups = XFRMGRP_ACQUIRE;
netlink_broadcast(xfrm_nl, skb, 0, XFRMGRP_ACQUIRE, GFP_ATOMIC);
return 0;
}
/* User gives us xfrm_user_policy_info followed by an array of 0
* or more templates.
*/
struct xfrm_policy *xfrm_compile_policy(int opt, u8 *data, int len, int *dir)
{
struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data;
struct xfrm_user_tmpl *ut = (struct xfrm_user_tmpl *) (p + 1);
struct xfrm_policy *xp;
int nr;
if (opt != IP_XFRM_POLICY) {
*dir = -EOPNOTSUPP;
return NULL;
}
*dir = -EINVAL;
if (len < sizeof(*p) ||
verify_newpolicy_info(p))
return NULL;
nr = ((len - sizeof(*p)) / sizeof(*ut));
if (nr > XFRM_MAX_DEPTH)
return NULL;
xp = xfrm_policy_alloc(GFP_KERNEL);
if (xp == NULL) {
*dir = -ENOBUFS;
return NULL;
}
copy_from_user_policy(xp, p);
copy_templates(xp, ut, nr);
*dir = p->dir;
return xp;
}
static struct xfrm_mgr netlink_mgr = {
.id = "netlink",
.notify = xfrm_send_notify,
.acquire = xfrm_send_acquire,
.compile_policy = xfrm_compile_policy,
};
static int __init xfrm_user_init(void)
{
printk(KERN_INFO "Initializing IPsec netlink socket\n");
xfrm_nl = netlink_kernel_create(NETLINK_XFRM, xfrm_netlink_rcv);
if (xfrm_nl == NULL)
panic("xfrm_user_init: cannot initialize xfrm_nl\n");
xfrm_register_km(&netlink_mgr);
return 0;
}
static void __exit xfrm_user_exit(void)
{
xfrm_unregister_km(&netlink_mgr);
sock_release(xfrm_nl->socket);
}
module_init(xfrm_user_init);
module_exit(xfrm_user_exit);
......@@ -296,6 +296,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, struct in6_addr *addr)
}
memset(mc, 0, sizeof(struct ifmcaddr6));
init_timer(&mc->mca_timer);
mc->mca_timer.function = igmp6_timer_handler;
mc->mca_timer.data = (unsigned long) mc;
......
......@@ -2364,6 +2364,7 @@ static int irda_getsockopt(struct socket *sock, int level, int optname,
/* Set watchdog timer to expire in <val> ms. */
self->errno = 0;
init_timer(&self->watchdog);
self->watchdog.function = irda_discovery_timeout;
self->watchdog.data = (unsigned long) self;
self->watchdog.expires = jiffies + (val * HZ/1000);
......
......@@ -528,8 +528,7 @@ static struct xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, void **
switch (((struct sockaddr *)(addr + 1))->sa_family) {
case AF_INET:
x = xfrm_state_lookup(
((struct sockaddr_in*)(addr + 1))->sin_addr.s_addr,
x = xfrm_state_lookup(((struct sockaddr_in*)(addr + 1))->sin_addr.s_addr,
sa->sadb_sa_spi, proto);
break;
case AF_INET6:
......@@ -1043,7 +1042,7 @@ static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
daddr = (struct sockaddr_in*)(addr + 1);
x = xfrm_find_acq(mode, reqid, proto, daddr->sin_addr.s_addr,
saddr->sin_addr.s_addr);
saddr->sin_addr.s_addr, 1);
if (x == NULL)
return -ENOENT;
......@@ -1122,7 +1121,17 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr,
/* XXX there is race condition */
x1 = pfkey_xfrm_state_lookup(hdr, ext_hdrs);
if (x1 && hdr->sadb_msg_type == SADB_ADD) {
if (!x1) {
x1 = xfrm_find_acq(x->props.mode, x->props.reqid, x->id.proto,
x->id.daddr.xfrm4_addr,
x->props.saddr.xfrm4_addr, 0);
if (x1 && x1->id.spi != x->id.spi && x1->id.spi) {
xfrm_state_put(x1);
x1 = NULL;
}
}
if (x1 && x1->id.spi && hdr->sadb_msg_type == SADB_ADD) {
x->km.state = XFRM_STATE_DEAD;
xfrm_state_put(x);
xfrm_state_put(x1);
......@@ -1131,7 +1140,7 @@ static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr,
xfrm_state_insert(x);
if (x1 && hdr->sadb_msg_type != SADB_ADD) {
if (x1) {
xfrm_state_delete(x1);
xfrm_state_put(x1);
}
......@@ -1225,7 +1234,7 @@ static struct sk_buff *compose_sadb_supported(struct sadb_msg *orig, int allocat
esp_len += sizeof(struct sadb_supported);
len = esp_len + ah_len + sizeof(struct sadb_msg);
skb = alloc_skb(allocation, len + 16);
skb = alloc_skb(len + 16, allocation);
if (!skb)
goto out_put_algs;
......@@ -2156,7 +2165,7 @@ static struct xfrm_policy *pfkey_compile_policy(int opt, u8 *data, int len, int
(!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir > IPSEC_DIR_OUTBOUND))
return NULL;
xp = xfrm_policy_alloc(GFP_KERNEL);
xp = xfrm_policy_alloc(GFP_ATOMIC);
if (xp == NULL) {
*dir = -ENOBUFS;
return NULL;
......
......@@ -181,18 +181,22 @@ int llc_sk_init(struct sock* sk)
llc->inc_cntr = llc->dec_cntr = 2;
llc->dec_step = llc->connect_step = 1;
init_timer(&llc->ack_timer);
llc->ack_timer.expire = LLC_ACK_TIME;
llc->ack_timer.timer.data = (unsigned long)sk;
llc->ack_timer.timer.function = llc_conn_ack_tmr_cb;
init_timer(&llc->pf_cycle_timer);
llc->pf_cycle_timer.expire = LLC_P_TIME;
llc->pf_cycle_timer.timer.data = (unsigned long)sk;
llc->pf_cycle_timer.timer.function = llc_conn_pf_cycle_tmr_cb;
init_timer(&llc->rej_sent_timer);
llc->rej_sent_timer.expire = LLC_REJ_TIME;
llc->rej_sent_timer.timer.data = (unsigned long)sk;
llc->rej_sent_timer.timer.function = llc_conn_rej_tmr_cb;
init_timer(&llc->busy_state_timer);
llc->busy_state_timer.expire = LLC_BUSY_TIME;
llc->busy_state_timer.timer.data = (unsigned long)sk;
llc->busy_state_timer.timer.function = llc_conn_busy_tmr_cb;
......@@ -552,6 +556,7 @@ static int __init llc_init(void)
skb_queue_head_init(&llc_main_station.mac_pdu_q);
skb_queue_head_init(&llc_main_station.ev_q.list);
spin_lock_init(&llc_main_station.ev_q.lock);
init_timer(&llc_main_station.ack_timer);
llc_main_station.ack_timer.data = (unsigned long)&llc_main_station;
llc_main_station.ack_timer.function = llc_station_ack_tmr_cb;
......
......@@ -411,9 +411,9 @@ static int sfq_init(struct Qdisc *sch, struct rtattr *opt)
struct sfq_sched_data *q = (struct sfq_sched_data *)sch->data;
int i;
init_timer(&q->perturb_timer);
q->perturb_timer.data = (unsigned long)sch;
q->perturb_timer.function = sfq_perturbation;
init_timer(&q->perturb_timer);
for (i=0; i<SFQ_HASH_DIVISOR; i++)
q->ht[i] = SFQ_DEPTH;
......
......@@ -66,6 +66,7 @@
#include <linux/interrupt.h>
#include <linux/netdevice.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/wanrouter.h>
#include <linux/netlink.h>
#include <linux/rtnetlink.h>
......@@ -1839,29 +1840,19 @@ void __init sock_init(void)
#endif
}
int socket_get_info(char *buffer, char **start, off_t offset, int length)
#ifdef CONFIG_PROC_FS
void socket_seq_show(struct seq_file *seq)
{
int len, cpu;
int cpu;
int counter = 0;
for (cpu=0; cpu<NR_CPUS; cpu++)
for (cpu = 0; cpu < NR_CPUS; cpu++)
counter += sockets_in_use[cpu].counter;
/* It can be negative, by the way. 8) */
if (counter < 0)
counter = 0;
len = sprintf(buffer, "sockets: used %d\n", counter);
if (offset >= len)
{
*start = buffer;
return 0;
}
*start = buffer + offset;
len -= offset;
if (len > length)
len = length;
if (len < 0)
len = 0;
return len;
seq_printf(seq, "sockets: used %d\n", counter);
}
#endif /* CONFIG_PROC_FS */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment